diff --git a/src/rockstor/storageadmin/migrations/0040_auto__add_dcontainerenv__add_unique_dcontainerenv_container_key__add_f.py b/src/rockstor/storageadmin/migrations/0040_auto__add_dcontainerenv__add_unique_dcontainerenv_container_key__add_f.py
new file mode 100644
index 000000000..7f4eeef23
--- /dev/null
+++ b/src/rockstor/storageadmin/migrations/0040_auto__add_dcontainerenv__add_unique_dcontainerenv_container_key__add_f.py
@@ -0,0 +1,565 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'DContainerEnv'
+ db.create_table(u'storageadmin_dcontainerenv', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('container', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['storageadmin.DContainer'])),
+ ('key', self.gf('django.db.models.fields.CharField')(max_length=1024)),
+ ('val', self.gf('django.db.models.fields.CharField')(max_length=1024, null=True)),
+ ('description', self.gf('django.db.models.fields.CharField')(max_length=2048, null=True)),
+ ('label', self.gf('django.db.models.fields.CharField')(max_length=64, null=True)),
+ ))
+ db.send_create_signal('storageadmin', ['DContainerEnv'])
+
+ # Adding unique constraint on 'DContainerEnv', fields ['container', 'key']
+ db.create_unique(u'storageadmin_dcontainerenv', ['container_id', 'key'])
+
+ # Adding field 'DContainer.uid'
+ db.add_column(u'storageadmin_dcontainer', 'uid',
+ self.gf('django.db.models.fields.IntegerField')(null=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'DContainerEnv', fields ['container', 'key']
+ db.delete_unique(u'storageadmin_dcontainerenv', ['container_id', 'key'])
+
+ # Deleting model 'DContainerEnv'
+ db.delete_table(u'storageadmin_dcontainerenv')
+
+ # Deleting field 'DContainer.uid'
+ db.delete_column(u'storageadmin_dcontainer', 'uid')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'oauth2_provider.application': {
+ 'Meta': {'object_name': 'Application'},
+ 'authorization_grant_type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'client_id': ('django.db.models.fields.CharField', [], {'default': "u'XIsUzfCj6XywVaoouJukWytqIYKRttTKUAyx0k4p'", 'unique': 'True', 'max_length': '100', 'db_index': 'True'}),
+ 'client_secret': ('django.db.models.fields.CharField', [], {'default': "u'PEskqf4naFRo89agOUI36xYuzf0t16n7tMolLeAsz7o51DLeXoGmWDuXJ2KjjrVr8ojLKUvjqn68zDCZgXOkVt7PpnC6LCj70uNWDIvdJcP29Q4fmIA4XhYLOsAkNFIK'", 'max_length': '255', 'db_index': 'True', 'blank': 'True'}),
+ 'client_type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'redirect_uris': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'skip_authorization': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'oauth2_provider_application'", 'to': u"orm['auth.User']"})
+ },
+ 'storageadmin.advancednfsexport': {
+ 'Meta': {'object_name': 'AdvancedNFSExport'},
+ 'export_str': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'storageadmin.apikeys': {
+ 'Meta': {'object_name': 'APIKeys'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
+ 'user': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '8'})
+ },
+ 'storageadmin.appliance': {
+ 'Meta': {'object_name': 'Appliance'},
+ 'client_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+ 'client_secret': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
+ 'current_appliance': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'hostname': ('django.db.models.fields.CharField', [], {'default': "'Rockstor'", 'max_length': '128'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'mgmt_port': ('django.db.models.fields.IntegerField', [], {'default': '443'}),
+ 'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
+ },
+ 'storageadmin.configbackup': {
+ 'Meta': {'object_name': 'ConfigBackup'},
+ 'config_backup': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'md5sum': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'size': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
+ },
+ 'storageadmin.containeroption': {
+ 'Meta': {'object_name': 'ContainerOption'},
+ 'container': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.DContainer']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'val': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'})
+ },
+ 'storageadmin.dashboardconfig': {
+ 'Meta': {'object_name': 'DashboardConfig'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'unique': 'True'}),
+ 'widgets': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
+ },
+ 'storageadmin.dcontainer': {
+ 'Meta': {'object_name': 'DContainer'},
+ 'dimage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.DImage']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'launch_order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '1024'}),
+ 'rockon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.RockOn']"}),
+ 'uid': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
+ },
+ 'storageadmin.dcontainerenv': {
+ 'Meta': {'unique_together': "(('container', 'key'),)", 'object_name': 'DContainerEnv'},
+ 'container': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.DContainer']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'val': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
+ },
+ 'storageadmin.dcontainerlink': {
+ 'Meta': {'unique_together': "(('destination', 'name'),)", 'object_name': 'DContainerLink'},
+ 'destination': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'destination_container'", 'to': "orm['storageadmin.DContainer']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'source': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['storageadmin.DContainer']", 'unique': 'True'})
+ },
+ 'storageadmin.dcustomconfig': {
+ 'Meta': {'unique_together': "(('rockon', 'key'),)", 'object_name': 'DCustomConfig'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'rockon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.RockOn']"}),
+ 'val': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
+ },
+ 'storageadmin.dimage': {
+ 'Meta': {'object_name': 'DImage'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'repo': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'tag': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'storageadmin.disk': {
+ 'Meta': {'object_name': 'Disk'},
+ 'btrfs_uuid': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'parted': ('django.db.models.fields.BooleanField', [], {}),
+ 'pool': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Pool']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
+ 'serial': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'smart_available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'smart_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'transport': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'vendor': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
+ },
+ 'storageadmin.dport': {
+ 'Meta': {'unique_together': "(('container', 'containerp'),)", 'object_name': 'DPort'},
+ 'container': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.DContainer']"}),
+ 'containerp': ('django.db.models.fields.IntegerField', [], {}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'hostp': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'hostp_default': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'protocol': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'uiport': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'storageadmin.dvolume': {
+ 'Meta': {'unique_together': "(('container', 'dest_dir'),)", 'object_name': 'DVolume'},
+ 'container': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.DContainer']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'dest_dir': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'min_size': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Share']", 'null': 'True'}),
+ 'uservol': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'storageadmin.emailclient': {
+ 'Meta': {'object_name': 'EmailClient'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '1024'}),
+ 'receiver': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'sender': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'smtp_server': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'storageadmin.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'admin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'gid': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'groupname': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'storageadmin.installedplugin': {
+ 'Meta': {'object_name': 'InstalledPlugin'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'install_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'plugin_meta': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Plugin']"})
+ },
+ 'storageadmin.iscsitarget': {
+ 'Meta': {'object_name': 'IscsiTarget'},
+ 'dev_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
+ 'dev_size': ('django.db.models.fields.IntegerField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Share']"}),
+ 'tid': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'tname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
+ },
+ 'storageadmin.netatalkshare': {
+ 'Meta': {'object_name': 'NetatalkShare'},
+ 'description': ('django.db.models.fields.CharField', [], {'default': "'afp on rockstor'", 'max_length': '1024'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'share': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'netatalkshare'", 'unique': 'True', 'to': "orm['storageadmin.Share']"}),
+ 'time_machine': ('django.db.models.fields.CharField', [], {'default': "'yes'", 'max_length': '3'})
+ },
+ 'storageadmin.networkinterface': {
+ 'Meta': {'object_name': 'NetworkInterface'},
+ 'autoconnect': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True'}),
+ 'ctype': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'dname': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+ 'dns_servers': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'dspeed': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'dtype': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'gateway': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ipaddr': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'itype': ('django.db.models.fields.CharField', [], {'default': "'io'", 'max_length': '100'}),
+ 'mac': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+ 'method': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+ 'netmask': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'})
+ },
+ 'storageadmin.nfsexport': {
+ 'Meta': {'object_name': 'NFSExport'},
+ 'export_group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.NFSExportGroup']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mount': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ 'share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Share']"})
+ },
+ 'storageadmin.nfsexportgroup': {
+ 'Meta': {'object_name': 'NFSExportGroup'},
+ 'admin_host': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'editable': ('django.db.models.fields.CharField', [], {'default': "'rw'", 'max_length': '2'}),
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'host_str': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mount_security': ('django.db.models.fields.CharField', [], {'default': "'insecure'", 'max_length': '8'}),
+ 'nohide': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'syncable': ('django.db.models.fields.CharField', [], {'default': "'async'", 'max_length': '5'})
+ },
+ 'storageadmin.oauthapp': {
+ 'Meta': {'object_name': 'OauthApp'},
+ 'application': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['oauth2_provider.Application']", 'unique': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.User']"})
+ },
+ 'storageadmin.plugin': {
+ 'Meta': {'object_name': 'Plugin'},
+ 'css_file_name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ 'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}),
+ 'display_name': ('django.db.models.fields.CharField', [], {'default': "''", 'unique': 'True', 'max_length': '4096'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'js_file_name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'})
+ },
+ 'storageadmin.pool': {
+ 'Meta': {'object_name': 'Pool'},
+ 'compression': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnt_options': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'raid': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'toc': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+ },
+ 'storageadmin.poolbalance': {
+ 'Meta': {'object_name': 'PoolBalance'},
+ 'end_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'percent_done': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pool': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Pool']"}),
+ 'start_time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'started'", 'max_length': '10'}),
+ 'tid': ('django.db.models.fields.CharField', [], {'max_length': '36', 'null': 'True'})
+ },
+ 'storageadmin.poolscrub': {
+ 'Meta': {'object_name': 'PoolScrub'},
+ 'corrected_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'csum_discards': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'csum_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'data_extents_scrubbed': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'end_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'kb_scrubbed': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
+ 'last_physical': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'malloc_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'no_csum': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pid': ('django.db.models.fields.IntegerField', [], {}),
+ 'pool': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Pool']"}),
+ 'read_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'start_time': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'started'", 'max_length': '10'}),
+ 'super_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tree_bytes_scrubbed': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'tree_extents_scrubbed': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'uncorrectable_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'unverified_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'verify_errors': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'storageadmin.posixacls': {
+ 'Meta': {'object_name': 'PosixACLs'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.CharField', [], {'max_length': '5'}),
+ 'perms': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
+ 'smb_share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SambaShare']"})
+ },
+ 'storageadmin.rockon': {
+ 'Meta': {'object_name': 'RockOn'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'https': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'icon': ('django.db.models.fields.URLField', [], {'max_length': '1024', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'link': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'more_info': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'ui': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'volume_add_support': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'website': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True'})
+ },
+ 'storageadmin.sambacustomconfig': {
+ 'Meta': {'object_name': 'SambaCustomConfig'},
+ 'custom_config': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'smb_share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SambaShare']"})
+ },
+ 'storageadmin.sambashare': {
+ 'Meta': {'object_name': 'SambaShare'},
+ 'browsable': ('django.db.models.fields.CharField', [], {'default': "'yes'", 'max_length': '3'}),
+ 'comment': ('django.db.models.fields.CharField', [], {'default': "'foo bar'", 'max_length': '100'}),
+ 'guest_ok': ('django.db.models.fields.CharField', [], {'default': "'no'", 'max_length': '3'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'read_only': ('django.db.models.fields.CharField', [], {'default': "'no'", 'max_length': '3'}),
+ 'shadow_copy': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'share': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'sambashare'", 'unique': 'True', 'to': "orm['storageadmin.Share']"}),
+ 'snapshot_prefix': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'})
+ },
+ 'storageadmin.setup': {
+ 'Meta': {'object_name': 'Setup'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'setup_disks': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'setup_network': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'setup_system': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'setup_user': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'storageadmin.sftp': {
+ 'Meta': {'object_name': 'SFTP'},
+ 'editable': ('django.db.models.fields.CharField', [], {'default': "'ro'", 'max_length': '2'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'share': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['storageadmin.Share']", 'unique': 'True'})
+ },
+ 'storageadmin.share': {
+ 'Meta': {'object_name': 'Share'},
+ 'compression_algo': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'eusage': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'group': ('django.db.models.fields.CharField', [], {'default': "'root'", 'max_length': '4096'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
+ 'owner': ('django.db.models.fields.CharField', [], {'default': "'root'", 'max_length': '4096'}),
+ 'perms': ('django.db.models.fields.CharField', [], {'default': "'755'", 'max_length': '9'}),
+ 'pool': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Pool']"}),
+ 'pqgroup': ('django.db.models.fields.CharField', [], {'default': "'-1/-1'", 'max_length': '32'}),
+ 'qgroup': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'replica': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'rusage': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'subvol_name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ 'toc': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+ },
+ 'storageadmin.smartattribute': {
+ 'Meta': {'object_name': 'SMARTAttribute'},
+ 'aid': ('django.db.models.fields.IntegerField', [], {}),
+ 'atype': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'failed': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'flag': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'normed_value': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'raw_value': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'threshold': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'updated': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'worst': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'storageadmin.smartcapability': {
+ 'Meta': {'object_name': 'SMARTCapability'},
+ 'capabilities': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'flag': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'storageadmin.smarterrorlog': {
+ 'Meta': {'object_name': 'SMARTErrorLog'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'line': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'storageadmin.smarterrorlogsummary': {
+ 'Meta': {'object_name': 'SMARTErrorLogSummary'},
+ 'details': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'error_num': ('django.db.models.fields.IntegerField', [], {}),
+ 'etype': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'lifetime_hours': ('django.db.models.fields.IntegerField', [], {}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'storageadmin.smartidentity': {
+ 'Meta': {'object_name': 'SMARTIdentity'},
+ 'assessment': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'ata_version': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'capacity': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'device_model': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'enabled': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'firmware_version': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_smartdb': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'model_family': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'rotation_rate': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'sata_version': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'scanned_on': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'sector_size': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'serial_number': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'supported': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'world_wide_name': ('django.db.models.fields.CharField', [], {'max_length': '64'})
+ },
+ 'storageadmin.smartinfo': {
+ 'Meta': {'object_name': 'SMARTInfo'},
+ 'disk': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Disk']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'toc': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ },
+ 'storageadmin.smarttestlog': {
+ 'Meta': {'object_name': 'SMARTTestLog'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'lba_of_first_error': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'lifetime_hours': ('django.db.models.fields.IntegerField', [], {}),
+ 'pct_completed': ('django.db.models.fields.IntegerField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'test_num': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'storageadmin.smarttestlogdetail': {
+ 'Meta': {'object_name': 'SMARTTestLogDetail'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.SMARTInfo']"}),
+ 'line': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'storageadmin.snapshot': {
+ 'Meta': {'unique_together': "(('share', 'name'),)", 'object_name': 'Snapshot'},
+ 'eusage': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
+ 'qgroup': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'default': "'unknownsnap'", 'max_length': '4096'}),
+ 'rusage': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'share': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Share']"}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'snap_type': ('django.db.models.fields.CharField', [], {'default': "'admin'", 'max_length': '64'}),
+ 'toc': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'uvisible': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'writable': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'storageadmin.supportcase': {
+ 'Meta': {'object_name': 'SupportCase'},
+ 'case_type': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notes': ('django.db.models.fields.TextField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '9'}),
+ 'zipped_log': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'storageadmin.tlscertificate': {
+ 'Meta': {'object_name': 'TLSCertificate'},
+ 'certificate': ('django.db.models.fields.CharField', [], {'max_length': '12288', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '12288', 'null': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '1024'})
+ },
+ 'storageadmin.updatesubscription': {
+ 'Meta': {'object_name': 'UpdateSubscription'},
+ 'appliance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Appliance']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '512'})
+ },
+ 'storageadmin.user': {
+ 'Meta': {'object_name': 'User'},
+ 'admin': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'gid': ('django.db.models.fields.IntegerField', [], {'default': '5000'}),
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['storageadmin.Group']", 'null': 'True', 'blank': 'True'}),
+ 'homedir': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'public_key': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True', 'blank': 'True'}),
+ 'shell': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'smb_shares': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'admin_users'", 'null': 'True', 'to': "orm['storageadmin.SambaShare']"}),
+ 'uid': ('django.db.models.fields.IntegerField', [], {'default': '5000'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'suser'", 'unique': 'True', 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'default': "''", 'unique': 'True', 'max_length': '4096'})
+ }
+ }
+
+ complete_apps = ['storageadmin']
\ No newline at end of file
diff --git a/src/rockstor/storageadmin/models/__init__.py b/src/rockstor/storageadmin/models/__init__.py
index cad3bd277..ff30c40b7 100644
--- a/src/rockstor/storageadmin/models/__init__.py
+++ b/src/rockstor/storageadmin/models/__init__.py
@@ -44,7 +44,8 @@
from pool_balance import PoolBalance
from tls_certificate import TLSCertificate
from rockon import (RockOn, DImage, DContainer, DPort, DVolume,
- ContainerOption, DCustomConfig, DContainerLink)
+ ContainerOption, DCustomConfig, DContainerLink,
+ DContainerEnv)
from smart import (SMARTAttribute, SMARTCapability, SMARTErrorLog,
SMARTErrorLogSummary, SMARTTestLog, SMARTTestLogDetail,
SMARTIdentity, SMARTInfo)
diff --git a/src/rockstor/storageadmin/models/rockon.py b/src/rockstor/storageadmin/models/rockon.py
index 6876c5c2b..9f93a44ec 100644
--- a/src/rockstor/storageadmin/models/rockon.py
+++ b/src/rockstor/storageadmin/models/rockon.py
@@ -62,6 +62,10 @@ class DContainer(models.Model):
dimage = models.ForeignKey(DImage)
name = models.CharField(max_length=1024, unique=True)
launch_order = models.IntegerField(default=1)
+ #if uid is None, container's owner is not set. defaults to root.
+ #if it's -1, then owner is set to the owner of first volume, if any.
+ #if it's an integer other than -1, like 0, then owner is set to that uid.
+ uid = models.IntegerField(null=True)
class Meta:
app_label = 'storageadmin'
@@ -131,3 +135,15 @@ class DCustomConfig(models.Model):
class Meta:
unique_together = ('rockon', 'key',)
app_label = 'storageadmin'
+
+
+class DContainerEnv(models.Model):
+ container = models.ForeignKey(DContainer)
+ key = models.CharField(max_length=1024)
+ val = models.CharField(max_length=1024, null=True)
+ description = models.CharField(max_length=2048, null=True)
+ label = models.CharField(max_length=64, null=True)
+
+ class Meta:
+ unique_together = ('container', 'key')
+ app_label = 'storageadmin'
diff --git a/src/rockstor/storageadmin/serializers.py b/src/rockstor/storageadmin/serializers.py
index f93bf5b6d..092c21cdb 100644
--- a/src/rockstor/storageadmin/serializers.py
+++ b/src/rockstor/storageadmin/serializers.py
@@ -24,11 +24,12 @@
NFSExportGroup, SFTP, AdvancedNFSExport,
OauthApp, NetatalkShare, Group, PoolBalance,
SambaCustomConfig, TLSCertificate, RockOn,
- DVolume, DPort, DCustomConfig, SMARTAttribute,
- SMARTCapability, SMARTInfo, SMARTErrorLog,
- SMARTErrorLogSummary, SMARTTestLog,
- SMARTTestLogDetail, SMARTIdentity,
- ConfigBackup, EmailClient, UpdateSubscription)
+ DVolume, DPort, DCustomConfig, DContainerEnv,
+ SMARTAttribute, SMARTCapability, SMARTInfo,
+ SMARTErrorLog, SMARTErrorLogSummary,
+ SMARTTestLog, SMARTTestLogDetail,
+ SMARTIdentity, ConfigBackup, EmailClient,
+ UpdateSubscription)
from django.contrib.auth.models import User as DjangoUser
@@ -209,6 +210,9 @@ class RockOnCustomConfigSerializer(serializers.ModelSerializer):
class Meta:
model = DCustomConfig
+class RockOnEnvironmentSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = DContainerEnv
class SMARTCapabilitySerializer(serializers.ModelSerializer):
class Meta:
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js
index 171568d5b..4fcb54d49 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js
+++ b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js
@@ -642,6 +642,27 @@ var RockOnCustomConfigCollection = RockStorPaginatedCollection.extend({
}
});
+var RockOnEnvironment = Backbone.Model.extend({
+ urlRoot: '/api/rockon/environment/' + this.rid
+});
+
+var RockOnEnvironmentCollection = RockStorPaginatedCollection.extend({
+ model: RockOnEnvironment,
+ initialize: function(models, options) {
+ this.constructor.__super__.initialize.apply(this, arguments);
+ if (options) {
+ this.rid = options.rid;
+ }
+ },
+ baseUrl: function() {
+ if (this.rid) {
+ return '/api/rockons/environment/' + this.rid;
+ } else {
+ return '/api/rockons/environment';
+ }
+ }
+});
+
var EmailAccount = Backbone.Model.extend({
urlRoot: '/api/email'
});
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js
index c49b9eca3..03d6a3293 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js
+++ b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js
@@ -493,7 +493,7 @@ RockstorWizardPage = Backbone.View.extend({
render: function() {
$(this.el).html(this.template({
- model: this.model,
+ model: this.model
}));
return this;
},
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/templates/rockons/more_info.jst b/src/rockstor/storageadmin/static/storageadmin/js/templates/rockons/more_info.jst
index 06ea2360b..fa70887af 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/templates/rockons/more_info.jst
+++ b/src/rockstor/storageadmin/static/storageadmin/js/templates/rockons/more_info.jst
@@ -1 +1 @@
-{{rockonMoreInfo}}
+{{{rockonMoreInfo}}}
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/rockons.js b/src/rockstor/storageadmin/static/storageadmin/js/views/rockons.js
index 21e558055..4441727e7 100644
--- a/src/rockstor/storageadmin/static/storageadmin/js/views/rockons.js
+++ b/src/rockstor/storageadmin/static/storageadmin/js/views/rockons.js
@@ -27,1066 +27,1167 @@
RockonsView = RockstorLayoutView.extend({
- initialize: function() {
- this.constructor.__super__.initialize.apply(this, arguments);
- this.template = window.JST.rockons_rockons;
- this.rockons = new RockOnCollection({});
- this.service = new Service({ name: 'docker' });
- this.dependencies.push(this.rockons, this.service);
- this.updateFreq = 15000;
- this.defTab = 0;
- this.initHandlebarHelpers();
- },
-
- events: {
- 'switchChange.bootstrapSwitch': 'rockonToggle',
- 'click #js-install-rockon': 'installRockon',
- 'click #js-uninstall-rockon': 'uninstallRockon',
- 'click #js-rockons-installed': 'installedRockons',
- 'click #js-update-rockons': 'updateRockons',
- 'click #js-rockon-settings': 'rockonSettings',
- 'click #js-rockon-info': 'rockonInfo'
- },
-
- render: function() {
- this.service.fetch();
- this.rockons.fetch();
- this.updateStatus();
-
- return this;
- },
-
- renderRockons: function() {
- var _this = this;
-
- var ui_map = {};
- var uis = this.rockons.filter(function(rockon) {
- ui_map[rockon.get('id')] = null;
- if (rockon.get('ui')) {
- var protocol = "http://";
- if (rockon.get('https')) {
- protocol = "https://";
- }
- var ui_link = protocol + window.location.hostname;
- if (rockon.get('ui_port')) {
- ui_link += ":" + rockon.get('ui_port');
- }
- if (rockon.get('link')) {
- ui_link += "/" + rockon.get('link');
- }
- ui_map[rockon.get('id')] = ui_link;
- }
- return false;
- });
-
- $(this.el).html(this.template({
- rockons: this.rockons,
- status: this.service.get('status'),
- ui_map: ui_map
- }));
-
- if (!this.dockerServiceView) {
- this.dockerServiceView = new DockerServiceView({
- parentView: this,
- dockerService: this.dockerService
- });
+ initialize: function() {
+ this.constructor.__super__.initialize.apply(this, arguments);
+ this.template = window.JST.rockons_rockons;
+ this.rockons = new RockOnCollection({});
+ this.service = new Service({ name: 'docker' });
+ this.dependencies.push(this.rockons, this.service);
+ this.updateFreq = 15000;
+ this.defTab = 0;
+ this.initHandlebarHelpers();
+ },
+
+ events: {
+ 'switchChange.bootstrapSwitch': 'rockonToggle',
+ 'click #js-install-rockon': 'installRockon',
+ 'click #js-uninstall-rockon': 'uninstallRockon',
+ 'click #js-rockons-installed': 'installedRockons',
+ 'click #js-update-rockons': 'updateRockons',
+ 'click #js-rockon-settings': 'rockonSettings',
+ 'click #js-rockon-info': 'rockonInfo'
+ },
+
+ render: function() {
+ this.service.fetch();
+ this.rockons.fetch();
+ this.updateStatus();
+
+ return this;
+ },
+
+ renderRockons: function() {
+ var _this = this;
+
+ var ui_map = {};
+ var uis = this.rockons.filter(function(rockon) {
+ ui_map[rockon.get('id')] = null;
+ if (rockon.get('ui')) {
+ var protocol = "http://";
+ if (rockon.get('https')) {
+ protocol = "https://";
}
- // Render the Rockons template with a status describing whether
- // the Rockons service has been enabled
-
- $('#docker-service-ph').append(this.dockerServiceView.render().el);
-
- $('#install-rockon-overlay').overlay({load: false});
- this.$("ul.nav.nav-tabs").tabs("div.css-panes > div");
- this.$('.nav-tabs li:eq(' + this.defTab + ') a').click();
-
- //initalize bootstrap switch
- this.$("[type='checkbox']").bootstrapSwitch();
- this.$("[type='checkbox']").bootstrapSwitch('onColor','success'); //left side text color
- this.$("[type='checkbox']").bootstrapSwitch('offColor','danger'); //right side text color
- },
-
- installRockon: function(event) {
- var _this = this;
- this.defTab = 0;
- event.preventDefault();
- var button = $(event.currentTarget);
- var rockon_id = button.attr('data-name');
- var rockon_o = _this.rockons.get(rockon_id);
- var wizardView = new RockonInstallWizardView({
- model: new Backbone.Model({ rockon: rockon_o }),
- title: rockon_o.get('name') + ' install wizard',
- parent: this
- });
- $('.overlay-content', '#install-rockon-overlay').html(wizardView.render().el);
- $('#install-rockon-overlay').overlay().load();
- },
-
- uninstallRockon: function(event) {
- var _this = this;
- event.preventDefault();
- var button = $(event.currentTarget);
- if (buttonDisabled(button)) return false;
- var rockon_id = button.attr('data-name');
- var rockon_o = _this.rockons.get(rockon_id);
- if (confirm("Are you sure you want to uninstall this Rock-on (" + rockon_o.get('name') + ")?")) {
- disableButton(button);
- $.ajax({
- url: '/api/rockons/' + rockon_id + '/uninstall',
- type: 'POST',
- dataType: 'json',
- success: function() {
- _this.defTab = 0;
- _this.render();
- enableButton(button);
- },
- error: function(xhr, status, error) {
- enableButton(button);
- }
- });
+ var ui_link = protocol + window.location.hostname;
+ if (rockon.get('ui_port')) {
+ ui_link += ":" + rockon.get('ui_port');
}
- },
-
- updateRockons: function(event) {
- var _this = this;
- event.preventDefault();
- var button = $(event.currentTarget);
- if (buttonDisabled(button)) return false;
- disableButton(button);
- $.ajax({
- url: '/api/rockons/update',
- type: 'POST',
- dataType: 'json',
- success: function() {
- _this.defTab = 1;
- _this.render();
- enableButton(button);
- },
- error: function(xhr, status, error) {
- enableButton(button);
- }
- });
- },
-
- rockonSettings: function(event) {
- var _this = this;
- event.preventDefault();
- var rockon_id = _this.getRockonId(event);
- var rockon_o = _this.rockons.get(rockon_id);
- _this.stopPolling();
- var wizardView = new RockonSettingsWizardView({
- model: new Backbone.Model({ rockon: rockon_o}),
- title: rockon_o.get('name') + ' Settings',
- parent: this
- });
- $('.overlay-content', '#install-rockon-overlay').html(wizardView.render().el);
- $('#install-rockon-overlay').overlay().load();
- },
-
- rockonInfo: function(event) {
- var _this = this;
- event.preventDefault();
- var rockon_id = _this.getRockonId(event);
- var rockon_o = _this.rockons.get(rockon_id);
- _this.stopPolling();
- var infoView = new RockonInfoView({
- model: new Backbone.Model({ rockon: rockon_o}),
- title: 'Additional information about ' + rockon_o.get('name') + ' Rock-on',
- parent: this
- });
- $('.overlay-content', '#install-rockon-overlay').html(infoView.render().el);
- $('#install-rockon-overlay').overlay().load();
- },
-
- getRockonId: function(event) {
- var slider = $(event.currentTarget);
- return slider.attr('data-rockon-id');
- },
-
- rockonToggle: function(event,state){
- var rockonId = $(event.target).attr('data-rockon-id');
- if(state){
- this.startRockon(rockonId);
- }else{
- this.stopRockon(rockonId);
+ if (rockon.get('link')) {
+ ui_link += "/" + rockon.get('link');
}
- },
-
- startRockon: function(rockonId) {
- console.log(event);
- var _this = this;
- this.stopPolling();
- $.ajax({
- url: '/api/rockons/' + rockonId + '/start',
- type: 'POST',
- dataType: 'json',
- success: function(data, status, xhr) {
- _this.defTab = 0;
- _this.updateStatus();
- },
- error: function(data, status, xhr) {
- console.log('error while starting rockon');
- }
- });
- },
-
- stopRockon: function(rockonId) {
- var _this = this;
- this.stopPolling();
- $.ajax({
- url: '/api/rockons/' + rockonId + '/stop',
- type: 'POST',
- dataType: 'json',
- success: function(data, status, xhr) {
- _this.defTab = 0;
- _this.updateStatus();
- },
- error: function(data, status, xhr) {
- console.log('error while stopping rockon');
- }
- });
- },
-
- pendingOps: function() {
- var pending = this.rockons.find(function(rockon) {
- if ((rockon.get('status').search('pending') != -1) || (rockon.get('state').search('pending') != -1)) {
- return true;
- }
- });
- if (pending) { return true; }
- return false;
- },
-
- updateStatus: function() {
- var _this = this;
- _this.startTime = new Date().getTime();
- _this.rockons.fetch({
- silent: true,
- success: function(data, response, options) {
- _this.renderRockons();
- if (_this.pendingOps()) {
- var ct = new Date().getTime();
- var diff = ct - _this.startTime;
- if (diff > _this.updateFreq) {
- _this.updateStatus();
- } else {
- _this.timeoutId = window.setTimeout( function() {
- _this.updateStatus();
- }, _this.updateFreq - diff);
- }
- } else {
- _this.stopPolling();
- }
- }
- });
- },
-
- stopPolling: function() {
- if (!_.isUndefined(this.timeoutId)) {
- window.clearInterval(this.timeoutId);
- }
- },
-
- installedRockons: function(event) {
- if (this.pendingOps()) {
- this.updateStatus();
+ ui_map[rockon.get('id')] = ui_link;
+ }
+ return false;
+ });
+
+ $(this.el).html(this.template({
+ rockons: this.rockons,
+ status: this.service.get('status'),
+ ui_map: ui_map
+ }));
+
+ if (!this.dockerServiceView) {
+ this.dockerServiceView = new DockerServiceView({
+ parentView: this,
+ dockerService: this.dockerService
+ });
+ }
+ // Render the Rockons template with a status describing whether
+ // the Rockons service has been enabled
+
+ $('#docker-service-ph').append(this.dockerServiceView.render().el);
+
+ $('#install-rockon-overlay').overlay({load: false});
+ this.$("ul.nav.nav-tabs").tabs("div.css-panes > div");
+ this.$('.nav-tabs li:eq(' + this.defTab + ') a').click();
+
+ //initalize bootstrap switch
+ this.$("[type='checkbox']").bootstrapSwitch();
+ this.$("[type='checkbox']").bootstrapSwitch('onColor','success'); //left side text color
+ this.$("[type='checkbox']").bootstrapSwitch('offColor','danger'); //right side text color
+ },
+
+ installRockon: function(event) {
+ var _this = this;
+ this.defTab = 0;
+ event.preventDefault();
+ var button = $(event.currentTarget);
+ var rockon_id = button.attr('data-name');
+ var rockon_o = _this.rockons.get(rockon_id);
+ var wizardView = new RockonInstallWizardView({
+ model: new Backbone.Model({ rockon: rockon_o }),
+ title: rockon_o.get('name') + ' install wizard',
+ parent: this
+ });
+ $('.overlay-content', '#install-rockon-overlay').html(wizardView.render().el);
+ $('#install-rockon-overlay').overlay().load();
+ },
+
+ uninstallRockon: function(event) {
+ var _this = this;
+ event.preventDefault();
+ var button = $(event.currentTarget);
+ if (buttonDisabled(button)) return false;
+ var rockon_id = button.attr('data-name');
+ var rockon_o = _this.rockons.get(rockon_id);
+ if (confirm("Are you sure you want to uninstall this Rock-on (" + rockon_o.get('name') + ")?")) {
+ disableButton(button);
+ $.ajax({
+ url: '/api/rockons/' + rockon_id + '/uninstall',
+ type: 'POST',
+ dataType: 'json',
+ success: function() {
+ _this.defTab = 0;
+ _this.render();
+ enableButton(button);
+ },
+ error: function(xhr, status, error) {
+ enableButton(button);
}
- },
-
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_installedRockons', function(){
- var html = '';
- _this = this;
- var installed = 0;
- this.rockons.each(function(rockon, index) {
- if (rockon.get('state') == 'installed' || rockon.get('state').match('pending')) {
- installed += 1;
- html += '
';
- if (rockon.get('state').search('pending') > -1 || rockon.get('status').search('pending') > -1) {
- var text = 'Installing ...';
- if (rockon.get('state') == 'pending_uninstall') {
- text = 'Uninstalling ...';
- } else if (rockon.get('status') == 'pending_start') {
- text = 'Starting ...';
- } else if (rockon.get('status') == 'pending_stop') {
- text = 'Stopping ...';
- }
- html += '
';
- html += '
';
- html += '
';
- html += '
';
- html += '
' + text + '
';
- html += '
';
- html += '
';
- html += '
';
- }
- html += '
';
- html += '
';
- html += '
' + rockon.get('name') + ' ';
- html += '
' + rockon.get('description') + '
';
- html += '
Current status: ' + rockon.get('status') + ' ';
- html += '
';
- html += '
';
- html += '
';
- if (rockon.get('state') == 'installed' && !rockon.get('status').match('pending')) {
- if (rockon.get('status') == 'started') {
- html += '
';
- } else {
- html += '
';
- }
- html += '
 ';
- if (rockon.get('more_info')) {
- html += '
';
- }
- html += '
';
- if (ui_map[rockon.get('id')]) {
- if (rockon.get('status') == 'started') {
- html += '
' + rockon.get('name') + ' UI ';
- } else {
- html += '
' + rockon.get('name') + ' UI ';
- }
- }
- if (rockon.get('status') != 'started') {
- html += '
Uninstall ';
- }
-
- }
- html += '
';
- html += '
';
- html += '
';
- }
- });
- if (installed == 0) {
- html += '';
- html += '
';
- html += '
';
- html += '
There are no Rock-ons installed currently. ';
- html += '';
- html += '
';
- html += '
';
- }
- return new Handlebars.SafeString(html);
- });
-
- Handlebars.registerHelper('display_allRockons', function(){
- var html = '';
- var all = 0;
- this.rockons.each(function(rockon, index) {
- if (rockon.get('state') == 'available' || rockon.get('state') == 'install_failed') {
- all += 1;
- html += '';
- html += '
';
- html += '
';
- html += '
' + rockon.get('name') + ' ';
- html += '
' + rockon.get('description') + '
';
- if (rockon.get('state') == 'install_failed') {
- html += '
Failed to install in the previous attempt. Here\'s how you can proceed.';
- html += '
';
- html += 'Check logs in /opt/rockstor/var/log for clues. ';
- html += 'Install again. ';
- html += 'If the problem persists, post on the Forum or email support@rockstor.com ';
- html += ' ';
- }
- html += '
Install ';
- html += '
';
- html += '
';
- html += '
';
- }
- });
- if (all == 0) {
- html += '';
- html += '
';
- html += '
';
- html += '
Click on Update button to check for new Rock-ons. ';
- html += '';
- html += '
';
- html += '
';
- }
- return new Handlebars.SafeString(html);
- });
+ });
}
+ },
+
+ updateRockons: function(event) {
+ var _this = this;
+ event.preventDefault();
+ var button = $(event.currentTarget);
+ if (buttonDisabled(button)) return false;
+ disableButton(button);
+ $.ajax({
+ url: '/api/rockons/update',
+ type: 'POST',
+ dataType: 'json',
+ success: function() {
+ _this.defTab = 1;
+ _this.render();
+ enableButton(button);
+ },
+ error: function(xhr, status, error) {
+ enableButton(button);
+ }
+ });
+ },
+
+ rockonSettings: function(event) {
+ var _this = this;
+ event.preventDefault();
+ var rockon_id = _this.getRockonId(event);
+ var rockon_o = _this.rockons.get(rockon_id);
+ _this.stopPolling();
+ var wizardView = new RockonSettingsWizardView({
+ model: new Backbone.Model({ rockon: rockon_o}),
+ title: rockon_o.get('name') + ' Settings',
+ parent: this
+ });
+ $('.overlay-content', '#install-rockon-overlay').html(wizardView.render().el);
+ $('#install-rockon-overlay').overlay().load();
+ },
+
+ rockonInfo: function(event) {
+ var _this = this;
+ event.preventDefault();
+ var rockon_id = _this.getRockonId(event);
+ var rockon_o = _this.rockons.get(rockon_id);
+ _this.stopPolling();
+ var infoView = new RockonInfoView({
+ model: new Backbone.Model({ rockon: rockon_o}),
+ title: 'Additional information about ' + rockon_o.get('name') + ' Rock-on',
+ parent: this
+ });
+ $('.overlay-content', '#install-rockon-overlay').html(infoView.render().el);
+ $('#install-rockon-overlay').overlay().load();
+ },
+
+ getRockonId: function(event) {
+ var slider = $(event.currentTarget);
+ return slider.attr('data-rockon-id');
+ },
+
+ rockonToggle: function(event,state){
+ var rockonId = $(event.target).attr('data-rockon-id');
+ if(state){
+ this.startRockon(rockonId);
+ }else{
+ this.stopRockon(rockonId);
+ }
+ },
+
+ startRockon: function(rockonId) {
+ console.log(event);
+ var _this = this;
+ this.stopPolling();
+ $.ajax({
+ url: '/api/rockons/' + rockonId + '/start',
+ type: 'POST',
+ dataType: 'json',
+ success: function(data, status, xhr) {
+ _this.defTab = 0;
+ _this.updateStatus();
+ },
+ error: function(data, status, xhr) {
+ console.log('error while starting rockon');
+ }
+ });
+ },
+
+ stopRockon: function(rockonId) {
+ var _this = this;
+ this.stopPolling();
+ $.ajax({
+ url: '/api/rockons/' + rockonId + '/stop',
+ type: 'POST',
+ dataType: 'json',
+ success: function(data, status, xhr) {
+ _this.defTab = 0;
+ _this.updateStatus();
+ },
+ error: function(data, status, xhr) {
+ console.log('error while stopping rockon');
+ }
+ });
+ },
+
+ pendingOps: function() {
+ var pending = this.rockons.find(function(rockon) {
+ if ((rockon.get('status').search('pending') != -1) || (rockon.get('state').search('pending') != -1)) {
+ return true;
+ }
+ });
+ if (pending) { return true; }
+ return false;
+ },
+
+ updateStatus: function() {
+ var _this = this;
+ _this.startTime = new Date().getTime();
+ _this.rockons.fetch({
+ silent: true,
+ success: function(data, response, options) {
+ _this.renderRockons();
+ if (_this.pendingOps()) {
+ var ct = new Date().getTime();
+ var diff = ct - _this.startTime;
+ if (diff > _this.updateFreq) {
+ _this.updateStatus();
+ } else {
+ _this.timeoutId = window.setTimeout( function() {
+ _this.updateStatus();
+ }, _this.updateFreq - diff);
+ }
+ } else {
+ _this.stopPolling();
+ }
+ }
+ });
+ },
-});
-
+ stopPolling: function() {
+ if (!_.isUndefined(this.timeoutId)) {
+ window.clearInterval(this.timeoutId);
+ }
+ },
-RockonInstallWizardView = WizardView.extend({
- initialize: function() {
- WizardView.prototype.initialize.apply(this, arguments);
- this.pages = [];
- this.rockon = this.model.get('rockon');
- this.volumes = new RockOnVolumeCollection(null, {rid: this.rockon.id});
- this.ports = new RockOnPortCollection(null, {rid: this.rockon.id});
- this.custom_config = new RockOnCustomConfigCollection(null, {rid: this.rockon.id});
- },
-
- fetchVolumes: function() {
- var _this = this;
- this.volumes.fetch({
- success: function () {
- _this.model.set('volumes', _this.volumes);
- _this.fetchPorts();
+ installedRockons: function(event) {
+ if (this.pendingOps()) {
+ this.updateStatus();
+ }
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_installedRockons', function(){
+ var html = '';
+ _this = this;
+ var installed = 0;
+ this.rockons.each(function(rockon, index) {
+ if (rockon.get('state') == 'installed' || rockon.get('state').match('pending')) {
+ installed += 1;
+ html += '';
+ if (rockon.get('state').search('pending') > -1 || rockon.get('status').search('pending') > -1) {
+ var text = 'Installing ...';
+ if (rockon.get('state') == 'pending_uninstall') {
+ text = 'Uninstalling ...';
+ } else if (rockon.get('status') == 'pending_start') {
+ text = 'Starting ...';
+ } else if (rockon.get('status') == 'pending_stop') {
+ text = 'Stopping ...';
}
- });
- },
-
- fetchPorts: function() {
- var _this = this;
- this.ports.fetch({
- success: function() {
- _this.model.set('ports', _this.ports);
- _this.fetchCustomConfig();
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
' + text + '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ }
+ html += '
';
+ html += '
';
+ html += '
' + rockon.get('name') + ' ';
+ html += '
' + rockon.get('description') + '
';
+ html += '
Current status: ' + rockon.get('status') + ' ';
+ html += '
';
+ html += '
';
+ html += '
';
+ if (rockon.get('state') == 'installed' && !rockon.get('status').match('pending')) {
+ if (rockon.get('status') == 'started') {
+ html += '
';
+ } else {
+ html += '
';
}
- });
- },
-
- fetchCustomConfig: function() {
- var _this = this;
- this.custom_config.fetch({
- success: function() {
- _this.model.set('custom_config', _this.custom_config);
- _this.addPages();
+ html += '
 ';
+ if (rockon.get('more_info')) {
+ html += '
';
+ }
+ html += '
';
+ if (_this.ui_map[rockon.get('id')]) {
+ if (rockon.get('status') == 'started') {
+ html += '
' + rockon.get('name') + ' UI ';
+ } else {
+ html += '
' + rockon.get('name') + ' UI ';
+ }
+ }
+ if (rockon.get('status') != 'started') {
+ html += '
Uninstall ';
}
- });
- },
-
- render: function() {
- this.fetchVolumes();
- return this;
- },
- addPages: function() {
- if (this.volumes.length > 0) {
- this.pages.push(RockonShareChoice);
- }
- if (this.ports.length > 0) {
- this.pages.push(RockonPortChoice);
+ }
+ html += '
';
+ html += '
';
+ html += '
';
}
- if (this.custom_config.length > 0) {
- this.pages.push(RockonCustomChoice);
+ });
+ if (installed == 0) {
+ html += '';
+ html += '
';
+ html += '
';
+ html += '
There are no Rock-ons installed currently. ';
+ html += '';
+ html += '
';
+ html += '
';
+ }
+ return new Handlebars.SafeString(html);
+ });
+
+ Handlebars.registerHelper('display_allRockons', function(){
+ var html = '';
+ var all = 0;
+ this.rockons.each(function(rockon, index) {
+ if (rockon.get('state') == 'available' || rockon.get('state') == 'install_failed') {
+ all += 1;
+ html += '';
+ html += '
';
+ html += '
';
+ html += '
' + rockon.get('name') + ' ';
+ html += '
' + rockon.get('description') + '
';
+ if (rockon.get('state') == 'install_failed') {
+ html += '
Failed to install in the previous attempt. Here\'s how you can proceed.';
+ html += '
';
+ html += 'Check logs in /opt/rockstor/var/log for clues. ';
+ html += 'Install again. ';
+ html += 'If the problem persists, post on the Forum or email support@rockstor.com ';
+ html += ' ';
+ }
+ html += '
Install ';
+ html += '
';
+ html += '
';
+ html += '
';
}
- this.pages.push.apply(this.pages, [RockonInstallSummary, RockonInstallComplete]);
- WizardView.prototype.render.apply(this, arguments);
- return this;
- },
-
- setCurrentPage: function() {
- this.currentPage = new this.pages[this.currentPageNum]({
- model: this.model,
- parent: this,
- evAgg: this.evAgg
- });
- },
-
- modifyButtonText: function() {
- if (this.currentPageNum == (this.pages.length - 2)) {
- this.$('#next-page').html('Submit');
- } else if (this.currentPageNum == (this.pages.length - 1)) {
- this.$('#prev-page').hide();
- this.$('#next-page').html('Close');
- } else if (this.currentPageNum == 0) {
- this.$('#prev-page').hide();
- } else {
- this.$('#prev-page').show();
- this.$('#next-page').html('Next');
- this.$('#ph-wizard-buttons').show();
- }
- },
+ });
+ if (all == 0) {
+ html += '';
+ html += '
';
+ html += '
';
+ html += '
Click on Update button to check for new Rock-ons. ';
+ html += '';
+ html += '
';
+ html += '
';
+ }
+ return new Handlebars.SafeString(html);
+ });
+ }
+
+});
- lastPage: function() {
- return ((this.pages.length > 1)
- && ((this.pages.length-1) == this.currentPageNum));
- },
- finish: function() {
- this.parent.$('#install-rockon-overlay').overlay().close();
- this.parent.render();
+RockonInstallWizardView = WizardView.extend({
+ initialize: function() {
+ WizardView.prototype.initialize.apply(this, arguments);
+ this.pages = [];
+ this.rockon = this.model.get('rockon');
+ this.volumes = new RockOnVolumeCollection(null, {rid: this.rockon.id});
+ this.ports = new RockOnPortCollection(null, {rid: this.rockon.id});
+ this.custom_config = new RockOnCustomConfigCollection(null, {rid: this.rockon.id});
+ this.environment = new RockOnEnvironmentCollection(null, {rid: this.rockon.id});
+ },
+
+ fetchVolumes: function() {
+ var _this = this;
+ this.volumes.fetch({
+ success: function () {
+ _this.model.set('volumes', _this.volumes);
+ _this.fetchPorts();
+ }
+ });
+ },
+
+ fetchPorts: function() {
+ var _this = this;
+ this.ports.fetch({
+ success: function() {
+ _this.model.set('ports', _this.ports);
+ _this.fetchCustomConfig();
+ }
+ });
+ },
+
+ fetchCustomConfig: function() {
+ var _this = this;
+ this.custom_config.fetch({
+ success: function() {
+ _this.model.set('custom_config', _this.custom_config);
+ _this.fetchEnvironment();
+ }
+ });
+ },
+
+ fetchEnvironment: function() {
+ var _this = this;
+ this.environment.fetch({
+ success: function() {
+ _this.model.set('environment', _this.environment);
+ _this.addPages();
+ }
+ });
+ },
+
+ render: function() {
+ this.fetchVolumes();
+ return this;
+ },
+
+ addPages: function() {
+ if (this.volumes.length > 0) {
+ this.pages.push(RockonShareChoice);
+ }
+ if (this.ports.length > 0) {
+ this.pages.push(RockonPortChoice);
+ }
+ if (this.environment.length > 0) {
+ this.pages.push(RockonEnvironment);
+ }
+ if (this.custom_config.length > 0) {
+ this.pages.push(RockonCustomChoice);
}
+ this.pages.push.apply(this.pages, [RockonInstallSummary, RockonInstallComplete]);
+ WizardView.prototype.render.apply(this, arguments);
+ return this;
+ },
+
+ setCurrentPage: function() {
+ this.currentPage = new this.pages[this.currentPageNum]({
+ model: this.model,
+ parent: this,
+ evAgg: this.evAgg
+ });
+ },
+
+ modifyButtonText: function() {
+ if (this.currentPageNum == (this.pages.length - 2)) {
+ this.$('#next-page').html('Submit');
+ } else if (this.currentPageNum == (this.pages.length - 1)) {
+ this.$('#prev-page').hide();
+ this.$('#next-page').html('Close');
+ } else if (this.currentPageNum == 0) {
+ this.$('#prev-page').hide();
+ } else {
+ this.$('#prev-page').show();
+ this.$('#next-page').html('Next');
+ this.$('#ph-wizard-buttons').show();
+ }
+ },
+
+ lastPage: function() {
+ return ((this.pages.length > 1)
+ && ((this.pages.length-1) == this.currentPageNum));
+ },
+ finish: function() {
+ this.parent.$('#install-rockon-overlay').overlay().close();
+ this.parent.render();
+ }
});
RockonShareChoice = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_install_choice;
- this.vol_template = window.JST.rockons_vol_form;
- this.rockon = this.model.get('rockon');
- this.volumes = this.model.get('volumes');
- this.shares = new ShareCollection();
- this.shares.setPageSize(100);
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.shares.on('reset', this.renderVolumes, this);
- this.initHandlebarHelpers();
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.shares.fetch();
- return this;
- },
-
- renderVolumes: function() {
- this.$('#ph-vols-table').html(this.vol_template({volumes: this.volumes, shares: this.shares}));
- //form validation
- this.volForm = this.$('#vol-select-form');
- var rules = {};
- var messages = {};
- this.volumes.each(function(volume) {
- rules[volume.id] = { required: true };
- messages[volume.id] = "Please read the tooltip and make the right selection";
- });
- this.validator = this.volForm.validate({
- rules: rules,
- messages: messages
- });
- },
-
- save: function() {
-
- // Validate the form
- if (!this.volForm.valid()) {
- this.validator.showErrors();
- return $.Deferred().reject();
- }
+ initialize: function() {
+ this.template = window.JST.rockons_install_choice;
+ this.vol_template = window.JST.rockons_vol_form;
+ this.rockon = this.model.get('rockon');
+ this.volumes = this.model.get('volumes');
+ this.shares = new ShareCollection();
+ this.shares.setPageSize(100);
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.shares.on('reset', this.renderVolumes, this);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.shares.fetch();
+ return this;
+ },
+
+ renderVolumes: function() {
+ this.$('#ph-vols-table').html(this.vol_template({volumes: this.volumes, shares: this.shares}));
+ //form validation
+ this.volForm = this.$('#vol-select-form');
+ var rules = {};
+ var messages = {};
+ this.volumes.each(function(volume) {
+ rules[volume.id] = { required: true };
+ messages[volume.id] = "Please read the tooltip and make the right selection";
+ });
+ this.validator = this.volForm.validate({
+ rules: rules,
+ messages: messages
+ });
+ },
+
+ save: function() {
+
+ // Validate the form
+ if (!this.volForm.valid()) {
+ this.validator.showErrors();
+ return $.Deferred().reject();
+ }
- var share_map = {};
- var volumes = this.volumes.filter(function(volume) {
- share_map[volume.get('dest_dir')] = this.$('#' + volume.id).val();
- return volume;
- }, this);
- this.model.set('share_map', share_map);
- return $.Deferred().resolve();
- },
-
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_volumesForm', function(){
- var html = '';
- var _this = this;
- this.volumes.each(function(volume, index) {
- html += '';
- });
- return new Handlebars.SafeString(html);
+ var share_map = {};
+ var volumes = this.volumes.filter(function(volume) {
+ share_map[volume.get('dest_dir')] = this.$('#' + volume.id).val();
+ return volume;
+ }, this);
+ this.model.set('share_map', share_map);
+ return $.Deferred().resolve();
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_volumesForm', function(){
+ var html = '';
+ var _this = this;
+ this.volumes.each(function(volume, index) {
+ html += '';
+ });
+ return new Handlebars.SafeString(html);
+ });
+ }
});
RockonPortChoice = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_port_choice;
- this.port_template = window.JST.rockons_ports_form;
- this.ports = this.model.get('ports');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.initHandlebarHelpers();
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.$('#ph-ports-form').html(this.port_template({ports: this.ports}));
-
- // Add form validation
- this.portForm = this.$('#port-select-form');
- var rules = {};
- var messages = {};
- this.ports.each(function(port) {
- rules[port.id] = { required: true, number: true };
- messages[port.id] = "Please enter a valid port number";
- });
- this.validator = this.portForm.validate({
- rules: rules,
- messages: messages
- });
- return this;
- },
-
- save: function() {
-
- // Validate the form
- if (!this.portForm.valid()) {
- this.validator.showErrors();
- // return rejected promise so that the wizard doesn't proceed to the next page.
- return $.Deferred().reject();
- }
-
- var port_map = {};
- var cports = this.ports.filter(function(port) {
- port_map[this.$('#' + port.id).val()] = port.get('containerp');
- return port;
- }, this);
- this.model.set('port_map', port_map);
- return $.Deferred().resolve();
- },
-
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_portsForm', function(){
- var html = '';
- this.ports.each(function(port, index) {
- html += '';
- });
- return new Handlebars.SafeString(html);
- });
+ initialize: function() {
+ this.template = window.JST.rockons_port_choice;
+ this.port_template = window.JST.rockons_ports_form;
+ this.ports = this.model.get('ports');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-ports-form').html(this.port_template({ports: this.ports}));
+
+ // Add form validation
+ this.portForm = this.$('#port-select-form');
+ var rules = {};
+ var messages = {};
+ this.ports.each(function(port) {
+ rules[port.id] = { required: true, number: true };
+ messages[port.id] = "Please enter a valid port number";
+ });
+ this.validator = this.portForm.validate({
+ rules: rules,
+ messages: messages
+ });
+ return this;
+ },
+
+ save: function() {
+
+ // Validate the form
+ if (!this.portForm.valid()) {
+ this.validator.showErrors();
+ // return rejected promise so that the wizard doesn't proceed to the next page.
+ return $.Deferred().reject();
}
+
+ var port_map = {};
+ var cports = this.ports.filter(function(port) {
+ port_map[this.$('#' + port.id).val()] = port.get('containerp');
+ return port;
+ }, this);
+ this.model.set('port_map', port_map);
+ return $.Deferred().resolve();
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_portsForm', function(){
+ var html = '';
+ this.ports.each(function(port, index) {
+ html += '';
+ });
+ return new Handlebars.SafeString(html);
+ });
+ }
});
RockonCustomChoice = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_custom_choice;
- this.cc_template = window.JST.rockons_cc_form;
- this.custom_config = this.model.get('custom_config');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.initHandlebarHelpers();
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.$('#ph-cc-form').html(this.cc_template({cc: this.custom_config}));
- this.cc_form = this.$('#custom-choice-form');
- var rules = {};
- var messages = {};
- this.custom_config.each(function(cc) {
- rules[cc.id] = "required";
- messages[cc.id] = "This is a required field.";
- });
- this.validator = this.cc_form.validate({
- rules: rules,
- messages: messages
- });
- return this;
- },
+ initialize: function() {
+ this.template = window.JST.rockons_custom_choice;
+ this.cc_template = window.JST.rockons_cc_form;
+ this.custom_config = this.model.get('custom_config');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-cc-form').html(this.cc_template({cc: this.custom_config}));
+ this.cc_form = this.$('#custom-choice-form');
+ var rules = {};
+ var messages = {};
+ this.custom_config.each(function(cc) {
+ rules[cc.id] = "required";
+ messages[cc.id] = "This is a required field.";
+ });
+ this.validator = this.cc_form.validate({
+ rules: rules,
+ messages: messages
+ });
+ return this;
+ },
+
+ save: function() {
+ if (!this.cc_form.valid()) {
+ this.validator.showErrors();
+ return $.Deferred().reject();
+ }
+ var cc_map = {};
+ var cconfigs = this.custom_config.filter(function(cc) {
+ cc_map[cc.get('key')] = this.$('#' + cc.id).val();
+ return cc;
+ }, this);
+ this.model.set('cc_map', cc_map);
+ return $.Deferred().resolve();
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_ccForm', function(){
+ var html = '';
+ this.cc.each(function(cci, index) {
+ html += '';
+ });
+ return new Handlebars.SafeString(html);
+ });
+ }
+});
- save: function() {
- if (!this.cc_form.valid()) {
- this.validator.showErrors();
- return $.Deferred().reject();
- }
- var cc_map = {};
- var cconfigs = this.custom_config.filter(function(cc) {
- cc_map[cc.get('key')] = this.$('#' + cc.id).val();
- return cc;
- }, this);
- this.model.set('cc_map', cc_map);
- return $.Deferred().resolve();
- },
-
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_ccForm', function(){
- var html = '';
- this.cc.each(function(cci, index) {
- html += '';
- });
- return new Handlebars.SafeString(html);
- });
+RockonEnvironment = RockstorWizardPage.extend({
+ initialize: function() {
+ this.template = window.JST.rockons_custom_choice;
+ this.cc_template = window.JST.rockons_cc_form;
+ this.custom_config = this.model.get('environment');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-cc-form').html(this.cc_template({cc: this.custom_config}));
+ this.cc_form = this.$('#custom-choice-form');
+ var rules = {};
+ var messages = {};
+ this.custom_config.each(function(cc) {
+ rules[cc.id] = "required";
+ messages[cc.id] = "This is a required field.";
+ });
+ this.validator = this.cc_form.validate({
+ rules: rules,
+ messages: messages
+ });
+ return this;
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_ccForm', function(){
+ var html = '';
+ this.cc.each(function(cci, index) {
+ html += '';
+ });
+ return new Handlebars.SafeString(html);
+ });
+ },
+
+ save: function() {
+ if (!this.cc_form.valid()) {
+ this.validator.showErrors();
+ return $.Deferred().reject();
}
+ var env_map = {};
+ var envars = this.custom_config.filter(function(cvar) {
+ env_map[cvar.get('key')] = this.$('#' + cvar.id).val();
+ return cvar;
+ }, this);
+ this.model.set('env_map', env_map);
+ return $.Deferred().resolve();
+ }
});
RockonInstallSummary = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_install_summary;
- this.table_template = window.JST.rockons_summary_table;
- this.share_map = this.model.get('share_map');
- this.port_map = this.model.get('port_map');
- this.cc_map = this.model.get('cc_map');
- this.ports = this.model.get('ports');
- this.cc = this.model.get('custom_config');
- this.rockon = this.model.get('rockon');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.initHandlebarHelpers();
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.$('#ph-summary-table').html(this.table_template({
- share_map: this.share_map,
- port_map: this.port_map,
- cc_map: this.cc_map}));
- return this;
- },
-
- save: function() {
- var _this = this;
- //$('button#next-page').prop('disable', true);
- document.getElementById('next-page').disabled = true;
- return $.ajax({
- url: '/api/rockons/' + this.rockon.id + '/install',
- type: 'POST',
- dataType: 'json',
- contentType: 'application/json',
- data: JSON.stringify({
- 'ports': this.port_map,
- 'shares': this.share_map,
- 'cc': this.cc_map
- }),
- success: function() {
- document.getElementById('next-page').disabled = false;
- },
- error: function(request, status, error) { }
- });
- },
-
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_rockonsSummary_table', function(){
- var html = '';
- for (s in this.share_map) {
- html += '';
- html += 'Share ';
- html += '' + this.share_map[s] + ' ';
- html += '' + s + ' ';
- html += ' ';
- }
- for (p in this.port_map) {
- html += '';
- html += 'Port ';
- html += '' + this.port_map[p] + ' ';
- html += '' + p + ' ';
- html += ' ';
- }
- for (c in this.cc_map) {
- html += '';
- html += 'Custom ';
- html += '' + this.cc_map[c] + ' ';
- html += '' + c + ' ';
- html += ' ';
- }
- return new Handlebars.SafeString(html);
- });
- }
+ initialize: function() {
+ this.template = window.JST.rockons_install_summary;
+ this.table_template = window.JST.rockons_summary_table;
+ this.share_map = this.model.get('share_map');
+ this.port_map = this.model.get('port_map');
+ this.cc_map = this.model.get('cc_map');
+ this.env_map = this.model.get('env_map');
+ this.ports = this.model.get('ports');
+ this.environment = this.model.get('environment');
+ this.cc = this.model.get('custom_config');
+ this.rockon = this.model.get('rockon');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-summary-table').html(this.table_template({
+ share_map: this.share_map,
+ port_map: this.port_map,
+ cc_map: this.cc_map,
+ env_map: this.env_map}));
+ return this;
+ },
+
+ save: function() {
+ var _this = this;
+ //$('button#next-page').prop('disable', true);
+ document.getElementById('next-page').disabled = true;
+ return $.ajax({
+ url: '/api/rockons/' + this.rockon.id + '/install',
+ type: 'POST',
+ dataType: 'json',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ 'ports': this.port_map,
+ 'shares': this.share_map,
+ 'cc': this.cc_map,
+ 'environment': this.env_map
+ }),
+ success: function() {
+ document.getElementById('next-page').disabled = false;
+ },
+ error: function(request, status, error) { }
+ });
+ },
+
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_rockonsSummary_table', function(){
+ var html = '';
+ for (s in this.share_map) {
+ html += '';
+ html += 'Share ';
+ html += '' + this.share_map[s] + ' ';
+ html += '' + s + ' ';
+ html += ' ';
+ }
+ for (p in this.port_map) {
+ html += '';
+ html += 'Port ';
+ html += '' + this.port_map[p] + ' ';
+ html += '' + p + ' ';
+ html += ' ';
+ }
+ for (c in this.cc_map) {
+ html += '';
+ html += 'Custom ';
+ html += '' + this.cc_map[c] + ' ';
+ html += '' + c + ' ';
+ html += ' ';
+ }
+ for (e in this.env_map) {
+ html += '';
+ html += 'Env ';
+ html += '' + this.env_map[e] + ' ';
+ html += '' + e + ' ';
+ html += ' ';
+ }
+ return new Handlebars.SafeString(html);
+ });
+ }
});
RockonInstallComplete = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_install_complete;
- this.port_map = this.model.get('port_map');
- this.share_map = this.model.get('share_map');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- },
-
- render: function() {
- $(this.el).html(this.template({
- model: this.model,
- port_map: this.port_map,
- share_map: this.share_map
- }));
- return this;
- }
+ initialize: function() {
+ this.template = window.JST.rockons_install_complete;
+ this.port_map = this.model.get('port_map');
+ this.share_map = this.model.get('share_map');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ },
+
+ render: function() {
+ $(this.el).html(this.template({
+ model: this.model,
+ port_map: this.port_map,
+ share_map: this.share_map
+ }));
+ return this;
+ }
});
RockonInfoView = WizardView.extend({
- initialize: function() {
- WizardView.prototype.initialize.apply(this, arguments);
- this.pages = [RockonInfoSummary,];
- },
-
- render: function() {
- WizardView.prototype.render.apply(this, arguments);
- return this;
- },
-
- modifyButtonText: function() {
- this.$('#prev-page').hide();
- this.$('#next-page').hide();
- }
+ initialize: function() {
+ WizardView.prototype.initialize.apply(this, arguments);
+ this.pages = [RockonInfoSummary,];
+ },
+
+ render: function() {
+ WizardView.prototype.render.apply(this, arguments);
+ return this;
+ },
+
+ modifyButtonText: function() {
+ this.$('#prev-page').hide();
+ this.$('#next-page').hide();
+ }
});
RockonSettingsWizardView = WizardView.extend({
- initialize: function() {
- WizardView.prototype.initialize.apply(this, arguments);
- this.pages = [RockonSettingsSummary,];
- this.rockon = this.model.get('rockon');
- this.volumes = new RockOnVolumeCollection(null, {rid: this.rockon.id});
- this.ports = new RockOnPortCollection(null, {rid: this.rockon.id});
- this.custom_config = new RockOnCustomConfigCollection(null, {rid: this.rockon.id});
- this.shares = {};
- this.model.set('shares', this.shares);
- },
-
- fetchVolumes: function() {
- var _this = this;
- this.volumes.fetch({
- success: function () {
- _this.model.set('volumes', _this.volumes);
- _this.fetchPorts();
- }
- });
- },
-
- fetchPorts: function() {
- var _this = this;
- this.ports.fetch({
- success: function() {
- _this.model.set('ports', _this.ports);
- _this.fetchCustomConfig();
- }
- });
- },
-
- fetchCustomConfig: function() {
- var _this = this;
- this.custom_config.fetch({
- success: function() {
- _this.model.set('custom_config', _this.custom_config);
- _this.addPages();
- }
- });
- },
-
- render: function() {
- this.fetchVolumes();
- return this;
- },
-
- addPages: function() {
- if (this.rockon.get('volume_add_support')) {
- this.pages.push.apply(this.pages,
- [RockonAddShare, RockonSettingsSummary,
- RockonSettingsComplete]);
- }
- WizardView.prototype.render.apply(this, arguments);
- return this;
- },
-
- setCurrentPage: function() {
- this.currentPage = new this.pages[this.currentPageNum]({
- model: this.model,
- parent: this,
- evAgg: this.evAgg
- });
- },
-
- modifyButtonText: function() {
- if (this.currentPageNum == 0) {
- this.$('#prev-page').hide();
- this.$('#next-page').html('Add Storage');
- if (!this.rockon.get('volume_add_support')) {
- this.$('#next-page').hide();
- }
- } else if (this.currentPageNum == (this.pages.length - 2)) {
- this.$('#prev-page').html('Add Storage');
- this.$('#next-page').html('Next');
- } else if (this.currentPageNum == (this.pages.length - 1)) {
- this.$('#prev-page').hide();
- this.$('#next-page').html('Submit');
- } else {
- this.$('#prev-page').show();
- this.$('#next-page').html('Next');
- this.$('#ph-wizard-buttons').show();
- }
- },
+ initialize: function() {
+ WizardView.prototype.initialize.apply(this, arguments);
+ this.pages = [RockonSettingsSummary,];
+ this.rockon = this.model.get('rockon');
+ this.volumes = new RockOnVolumeCollection(null, {rid: this.rockon.id});
+ this.ports = new RockOnPortCollection(null, {rid: this.rockon.id});
+ this.custom_config = new RockOnCustomConfigCollection(null, {rid: this.rockon.id});
+ this.environment = new RockOnEnvironmentCollection(null, {rid: this.rockon.id});
+ this.shares = {};
+ this.model.set('shares', this.shares);
+ },
+
+ fetchVolumes: function() {
+ var _this = this;
+ this.volumes.fetch({
+ success: function () {
+ _this.model.set('volumes', _this.volumes);
+ _this.fetchPorts();
+ }
+ });
+ },
+
+ fetchPorts: function() {
+ var _this = this;
+ this.ports.fetch({
+ success: function() {
+ _this.model.set('ports', _this.ports);
+ _this.fetchCustomConfig();
+ }
+ });
+ },
+
+ fetchCustomConfig: function() {
+ var _this = this;
+ this.custom_config.fetch({
+ success: function() {
+ _this.model.set('custom_config', _this.custom_config);
+ _this.fetchEnvironment();
+ }
+ });
+ },
+
+ fetchEnvironment: function() {
+ var _this = this;
+ this.environment.fetch({
+ success: function() {
+ _this.model.set('environment', _this.environment);
+ _this.addPages();
+ }
+ });
+ },
+
+ render: function() {
+ this.fetchVolumes();
+ return this;
+ },
+
+ addPages: function() {
+ if (this.rockon.get('volume_add_support')) {
+ this.pages.push.apply(this.pages,
+ [RockonAddShare, RockonSettingsSummary,
+ RockonSettingsComplete]);
+ }
+ WizardView.prototype.render.apply(this, arguments);
+ return this;
+ },
+
+ setCurrentPage: function() {
+ this.currentPage = new this.pages[this.currentPageNum]({
+ model: this.model,
+ parent: this,
+ evAgg: this.evAgg
+ });
+ },
+
+ modifyButtonText: function() {
+ if (this.currentPageNum == 0) {
+ this.$('#prev-page').hide();
+ this.$('#next-page').html('Add Storage');
+ if (!this.rockon.get('volume_add_support')) {
+ this.$('#next-page').hide();
+ }
+ } else if (this.currentPageNum == (this.pages.length - 2)) {
+ this.$('#prev-page').html('Add Storage');
+ this.$('#next-page').html('Next');
+ } else if (this.currentPageNum == (this.pages.length - 1)) {
+ this.$('#prev-page').hide();
+ this.$('#next-page').html('Submit');
+ } else {
+ this.$('#prev-page').show();
+ this.$('#next-page').html('Next');
+ this.$('#ph-wizard-buttons').show();
+ }
+ },
- lastPage: function() {
- return ((this.pages.length > 1)
- && ((this.pages.length-1) == this.currentPageNum));
- },
+ lastPage: function() {
+ return ((this.pages.length > 1)
+ && ((this.pages.length-1) == this.currentPageNum));
+ },
- finish: function() {
- this.parent.$('#install-rockon-overlay').overlay().close();
- this.parent.render();
- }
+ finish: function() {
+ this.parent.$('#install-rockon-overlay').overlay().close();
+ this.parent.render();
+ }
});
RockonAddShare = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_add_shares;
- this.sub_template = window.JST.rockons_add_shares_form;
- this.shares = new ShareCollection();
- this.shares.setPageSize(100);
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.shares.on('reset', this.renderShares, this);
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.shares.fetch();
- return this;
- },
-
- renderShares: function() {
- this.share_map = this.model.get('shares');
- this.volumes = this.model.get('volumes');
- this.used_shares = [];
- var _this = this;
- this.volumes.each(function(volume, index) {
- _this.used_shares.push(volume.get('share_name'));
- });
- for (var s in this.share_map) {
- this.used_shares.push(s);
- }
- this.filtered_shares = this.shares.filter(function(share) {
- if (_this.used_shares.indexOf(share.get('name')) == -1) {
- return share;
- }
- }, this);
- this.$('#ph-add-shares-form').html(this.sub_template({
- shares: this.filtered_shares
- }));
- this.share_form = this.$('#vol-select-form');
- this.validator = this.share_form.validate({
- rules: { "volume": "required",
- "share": "required" },
- messages: { "volume": "Must be a valid unix path. Eg: /data/media",
- "share": "Select an appropriate Share to map"}
- });
- return this;
- },
-
- save: function() {
- if (!this.share_form.valid()) {
- this.validator.showErrors();
- return $.Deferred().reject();
- }
- this.share_map = this.model.get('shares');
- this.share_map[this.$('#volume').val()] = this.$('#share').val();
- this.model.set('shares', this.share_map);
- return $.Deferred().resolve();
+ initialize: function() {
+ this.template = window.JST.rockons_add_shares;
+ this.sub_template = window.JST.rockons_add_shares_form;
+ this.shares = new ShareCollection();
+ this.shares.setPageSize(100);
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.shares.on('reset', this.renderShares, this);
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.shares.fetch();
+ return this;
+ },
+
+ renderShares: function() {
+ this.share_map = this.model.get('shares');
+ this.volumes = this.model.get('volumes');
+ this.used_shares = [];
+ var _this = this;
+ this.volumes.each(function(volume, index) {
+ _this.used_shares.push(volume.get('share_name'));
+ });
+ for (var s in this.share_map) {
+ this.used_shares.push(s);
}
+ this.filtered_shares = this.shares.filter(function(share) {
+ if (_this.used_shares.indexOf(share.get('name')) == -1) {
+ return share;
+ }
+ }, this);
+ this.$('#ph-add-shares-form').html(this.sub_template({
+ shares: this.filtered_shares
+ }));
+ this.share_form = this.$('#vol-select-form');
+ this.validator = this.share_form.validate({
+ rules: { "volume": "required",
+ "share": "required" },
+ messages: { "volume": "Must be a valid unix path. Eg: /data/media",
+ "share": "Select an appropriate Share to map"}
+ });
+ return this;
+ },
+
+ save: function() {
+ if (!this.share_form.valid()) {
+ this.validator.showErrors();
+ return $.Deferred().reject();
+ }
+ this.share_map = this.model.get('shares');
+ this.share_map[this.$('#volume').val()] = this.$('#share').val();
+ this.model.set('shares', this.share_map);
+ return $.Deferred().resolve();
+ }
});
RockonInfoSummary = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_settings_summary;
- this.sub_template = window.JST.rockons_more_info;
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.$('#ph-settings-summary-table').html(this.sub_template({
- rockonMoreInfo: this.model.get('more_info'),
-
- }));
- return this;
- }
+ initialize: function() {
+ this.template = window.JST.rockons_settings_summary;
+ this.sub_template = window.JST.rockons_more_info;
+ this.rockon = this.model.get('rockon');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-settings-summary-table').html(this.sub_template({
+ rockonMoreInfo: this.rockon.get('more_info')
+ }));
+ return this;
+ }
});
RockonSettingsSummary = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_settings_summary;
- this.sub_template = window.JST.rockons_settings_summary_table;
- this.rockon = this.model.get('rockon');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- this.initHandlebarHelpers();
- },
-
- render: function() {
- RockstorWizardPage.prototype.render.apply(this, arguments);
- this.$('#ph-settings-summary-table').html(this.sub_template({
- model: this.model,
- volumes: this.model.get('volumes'),
- new_volumes: this.model.get('shares'),
- ports: this.model.get('ports'),
- cc: this.model.get('custom_config'),
- rockon: this.model.get('rockon')
- }));
- return this;
- },
- initHandlebarHelpers: function(){
- Handlebars.registerHelper('display_volumes', function(){
- var html = '';
- this.volumes.each(function(volume, index) {
- html += '';
- html += 'Share ';
- html += '' + volume.get('share_name') + ' ';
- html += '' + volume.get('dest_dir') + ' ';
- html += ' ';
- });
- return new Handlebars.SafeString(html);
- });
-
- Handlebars.registerHelper('display_newVolumes', function(){
- var html = '';
- for (share in this.new_volumes) {
- html += '';
- html += 'Share ';
- html += '' + this.new_volumes[share] + ' ';
- html += '' + share + ' ';
- html += ' ';
- }
- return new Handlebars.SafeString(html);
- });
-
- Handlebars.registerHelper('display_ports', function(){
- var html = '';
- this.ports.each(function(port, index) {
- html += '';
- html += 'Port ';
- html += '' + port.get('hostp') + ' ';
- html += '' + port.get('containerp') + ' ';
- html += ' ';
- });
- return new Handlebars.SafeString(html);
- });
-
- Handlebars.registerHelper('display_cc', function(){
- var html = '';
- this.cc.each(function(cci, index) {
- html += '';
- html += 'Custom ';
- html += '' + cci.get('val') + '   ';
- html += '' + cci.get('key') + ' ';
- html += ' ';
- });
- return new Handlebars.SafeString(html);
- });
-
- }
+ initialize: function() {
+ this.template = window.JST.rockons_settings_summary;
+ this.sub_template = window.JST.rockons_settings_summary_table;
+ this.rockon = this.model.get('rockon');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ this.initHandlebarHelpers();
+ },
+
+ render: function() {
+ RockstorWizardPage.prototype.render.apply(this, arguments);
+ this.$('#ph-settings-summary-table').html(this.sub_template({
+ model: this.model,
+ volumes: this.model.get('volumes'),
+ new_volumes: this.model.get('shares'),
+ ports: this.model.get('ports'),
+ cc: this.model.get('custom_config'),
+ env: this.model.get('environment'),
+ rockon: this.model.get('rockon')
+ }));
+ return this;
+ },
+ initHandlebarHelpers: function(){
+ Handlebars.registerHelper('display_volumes', function(){
+ var html = '';
+ this.volumes.each(function(volume, index) {
+ html += '';
+ html += 'Share ';
+ html += '' + volume.get('share_name') + ' ';
+ html += '' + volume.get('dest_dir') + ' ';
+ html += ' ';
+ });
+ return new Handlebars.SafeString(html);
+ });
+
+ Handlebars.registerHelper('display_newVolumes', function(){
+ var html = '';
+ for (share in this.new_volumes) {
+ html += '';
+ html += 'Share ';
+ html += '' + this.new_volumes[share] + ' ';
+ html += '' + share + ' ';
+ html += ' ';
+ }
+ return new Handlebars.SafeString(html);
+ });
+
+ Handlebars.registerHelper('display_ports', function(){
+ var html = '';
+ this.ports.each(function(port, index) {
+ html += '';
+ html += 'Port ';
+ html += '' + port.get('hostp') + ' ';
+ html += '' + port.get('containerp') + ' ';
+ html += ' ';
+ });
+ return new Handlebars.SafeString(html);
+ });
+
+ Handlebars.registerHelper('display_cc', function(){
+ var html = '';
+ this.cc.each(function(cci, index) {
+ html += '';
+ html += 'Custom ';
+ html += '' + cci.get('val') + '   ';
+ html += '' + cci.get('key') + ' ';
+ html += ' ';
+ });
+ //@todo: separate env and cc stuff.
+ this.env.each(function(envi, index) {
+ html += 'Env ';
+ html += '' + envi.get('val') + '   ';
+ html += '' + envi.get('key') + ' ';
+ });
+ return new Handlebars.SafeString(html);
+ });
+
+ }
});
RockonSettingsComplete = RockstorWizardPage.extend({
- initialize: function() {
- this.template = window.JST.rockons_update_complete;
- this.rockon = this.model.get('rockon');
- this.shares = this.model.get('shares');
- RockstorWizardPage.prototype.initialize.apply(this, arguments);
- },
-
- render: function() {
- $(this.el).html(this.template({
- model: this.model
- }));
- return this;
- },
-
- save: function() {
- var _this = this;
- if (document.getElementById('next-page').disabled) return false;
- document.getElementById('next-page').disabled = true;
- return $.ajax({
- url: '/api/rockons/' + this.rockon.id + '/update',
- type: 'POST',
- dataType: 'json',
- contentType: 'application/json',
- data: JSON.stringify({
- 'shares': this.shares
- }),
- success: function() {}
- });
- }
+ initialize: function() {
+ this.template = window.JST.rockons_update_complete;
+ this.rockon = this.model.get('rockon');
+ this.shares = this.model.get('shares');
+ RockstorWizardPage.prototype.initialize.apply(this, arguments);
+ },
+
+ render: function() {
+ $(this.el).html(this.template({
+ model: this.model
+ }));
+ return this;
+ },
+
+ save: function() {
+ var _this = this;
+ if (document.getElementById('next-page').disabled) return false;
+ document.getElementById('next-page').disabled = true;
+ return $.ajax({
+ url: '/api/rockons/' + this.rockon.id + '/update',
+ type: 'POST',
+ dataType: 'json',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ 'shares': this.shares
+ }),
+ success: function() {}
+ });
+ }
});
diff --git a/src/rockstor/storageadmin/urls/rockons.py b/src/rockstor/storageadmin/urls/rockons.py
index 44a3ecd91..0fcc34643 100644
--- a/src/rockstor/storageadmin/urls/rockons.py
+++ b/src/rockstor/storageadmin/urls/rockons.py
@@ -18,7 +18,8 @@
from django.conf.urls import patterns, url
from storageadmin.views import (RockOnView, RockOnIdView, RockOnVolumeView,
- RockOnPortView, RockOnCustomConfigView)
+ RockOnPortView, RockOnCustomConfigView,
+ RockOnEnvironmentView)
urlpatterns = patterns(
'',
@@ -26,6 +27,7 @@
url(r'^/volumes/(?P\d+)$', RockOnVolumeView.as_view(), ),
url(r'^/ports/(?P\d+)$', RockOnPortView.as_view(), ),
url(r'^/customconfig/(?P\d+)$', RockOnCustomConfigView.as_view(), ),
+ url(r'^/environment/(?P\d+)$', RockOnEnvironmentView.as_view(), ),
url(r'^/(?Pupdate)$', RockOnView.as_view(), ),
url(r'^/(?P\d+)$', RockOnIdView.as_view(), ),
url(r'^/(?P\d+)/(?Pinstall|uninstall|update|start|stop|state_update|status_update)$',
diff --git a/src/rockstor/storageadmin/views/__init__.py b/src/rockstor/storageadmin/views/__init__.py
index 88034ad37..89fed0751 100644
--- a/src/rockstor/storageadmin/views/__init__.py
+++ b/src/rockstor/storageadmin/views/__init__.py
@@ -47,6 +47,7 @@
from rockon_volume import RockOnVolumeView
from rockon_port import RockOnPortView
from rockon_custom_config import RockOnCustomConfigView
+from rockon_environment import RockOnEnvironmentView
from disk_smart import DiskSMARTDetailView
from config_backup import (ConfigBackupListView, ConfigBackupDetailView,
ConfigBackupUpload)
diff --git a/src/rockstor/storageadmin/views/rockon.py b/src/rockstor/storageadmin/views/rockon.py
index ecc7f271e..098d99c9c 100644
--- a/src/rockstor/storageadmin/views/rockon.py
+++ b/src/rockstor/storageadmin/views/rockon.py
@@ -21,7 +21,8 @@
from rest_framework.response import Response
from django.db import transaction
from storageadmin.models import (RockOn, DImage, DContainer, DPort, DVolume,
- ContainerOption, DCustomConfig, DContainerLink)
+ ContainerOption, DCustomConfig,
+ DContainerLink, DContainerEnv)
from storageadmin.serializers import RockOnSerializer
from storageadmin.util import handle_exception
import rest_framework_custom as rfc
@@ -149,128 +150,139 @@ def _create_update_meta(self, name, r_d):
if (not created):
co.dimage = io
co.launch_order = co_defaults['launch_order']
+ if ('uid' in c_d):
+ co.uid = int(c_d['uid'])
co.save()
- ports = {}
- if ('ports' in containers[c]):
- ports = containers[c]['ports']
- for p in ports:
- p_d = ports[p]
- if ('protocol' not in p_d):
- p_d['protocol'] = None
- p = int(p)
- po = None
- if (DPort.objects.filter(containerp=p, container=co).exists()):
- po = DPort.objects.get(containerp=p, container=co)
- po.hostp_default = p_d['host_default']
- po.description = p_d['description']
- po.protocol = p_d['protocol']
- po.label = p_d['label']
- else:
- #let's find next available default if default is already taken
- def_hostp = p_d['host_default']
- while (True):
- if (DPort.objects.filter(hostp=def_hostp).exists()):
- def_hostp += 1
- else:
- break
- po = DPort(description=p_d['description'],
- hostp=def_hostp, containerp=p,
- hostp_default=def_hostp,
- container=co,
- protocol=p_d['protocol'],
- label=p_d['label'])
- if ('ui' in p_d):
- po.uiport = p_d['ui']
- if (po.uiport):
- ro.ui = True
- ro.save()
- po.save()
+ ports = containers[c].get('ports', {})
+ for p in ports:
+ p_d = ports[p]
+ if ('protocol' not in p_d):
+ p_d['protocol'] = None
+ p = int(p)
+ po = None
+ if (DPort.objects.filter(containerp=p, container=co).exists()):
+ po = DPort.objects.get(containerp=p, container=co)
+ po.hostp_default = p_d['host_default']
+ po.description = p_d['description']
+ po.protocol = p_d['protocol']
+ po.label = p_d['label']
+ else:
+ #let's find next available default if default is already taken
+ def_hostp = p_d['host_default']
+ while (True):
+ if (DPort.objects.filter(hostp=def_hostp).exists()):
+ def_hostp += 1
+ else:
+ break
+ po = DPort(description=p_d['description'],
+ hostp=def_hostp, containerp=p,
+ hostp_default=def_hostp,
+ container=co,
+ protocol=p_d['protocol'],
+ label=p_d['label'])
+ if ('ui' in p_d):
+ po.uiport = p_d['ui']
+ if (po.uiport):
+ ro.ui = True
+ ro.save()
+ po.save()
ports = [int(p) for p in ports]
for po in DPort.objects.filter(container=co):
if (po.containerp not in ports):
po.delete()
- v_d = {}
- if ('volumes' in c_d):
- v_d = c_d['volumes']
- for v in v_d:
- cv_d = v_d[v]
- vo_defaults = {'description': cv_d['description'],
- 'label': cv_d['label']}
- vo, created = DVolume.objects.get_or_create(dest_dir=v, container=co,
- defaults=vo_defaults)
- if (not created):
- vo.description = vo_defaults['description']
- vo.label = vo_defaults['label']
- if ('min_size' in cv_d):
- vo.min_size = cv_d['min_size']
- vo.save()
+ v_d = c_d.get('volumes', {})
+ for v in v_d:
+ cv_d = v_d[v]
+ vo_defaults = {'description': cv_d['description'],
+ 'label': cv_d['label']}
+ vo, created = DVolume.objects.get_or_create(dest_dir=v, container=co,
+ defaults=vo_defaults)
+ if (not created):
+ vo.description = vo_defaults['description']
+ vo.label = vo_defaults['label']
+ if ('min_size' in cv_d):
+ vo.min_size = cv_d['min_size']
+ vo.save()
for vo in DVolume.objects.filter(container=co):
if (vo.dest_dir not in v_d):
vo.delete()
- if ('opts' in containers[c]):
- options = containers[c]['opts']
- id_l = []
- for o in options:
- #there are no unique constraints on this model, so we need this bandaid.
- if (ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).count() > 1):
- ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).delete()
- oo, created = ContainerOption.objects.get_or_create(container=co,
- name=o[0],
- val=o[1])
- id_l.append(oo.id)
- for oo in ContainerOption.objects.filter(container=co):
- if (oo.id not in id_l):
- oo.delete()
+ self._update_env(co, c_d)
+ options = containers[c].get('opts', [])
+ id_l = []
+ for o in options:
+ #there are no unique constraints on this model, so we need this bandaid.
+ if (ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).count() > 1):
+ ContainerOption.objects.filter(container=co, name=o[0], val=o[1]).delete()
+ oo, created = ContainerOption.objects.get_or_create(container=co,
+ name=o[0],
+ val=o[1])
+ id_l.append(oo.id)
+ for oo in ContainerOption.objects.filter(container=co):
+ if (oo.id not in id_l):
+ oo.delete()
- if ('container_links' in r_d):
- l_d = r_d['container_links']
- for cname in l_d:
- ll = l_d[cname]
- lsources = [l['source_container'] for l in ll]
- co = DContainer.objects.get(rockon=ro, name=cname)
- for clo in co.destination_container.all():
- if (clo.name not in lsources):
- clo.delete()
- for cl_d in ll:
- sco = DContainer.objects.get(rockon=ro, name=cl_d['source_container'])
- clo, created = DContainerLink.objects.get_or_create(source=sco,
- destination=co)
- clo.name = cl_d['name']
- clo.save()
+ l_d = r_d.get('container_links', {})
+ for cname in l_d:
+ ll = l_d[cname]
+ lsources = [l['source_container'] for l in ll]
+ co = DContainer.objects.get(rockon=ro, name=cname)
+ for clo in co.destination_container.all():
+ if (clo.name not in lsources):
+ clo.delete()
+ for cl_d in ll:
+ sco = DContainer.objects.get(rockon=ro, name=cl_d['source_container'])
+ clo, created = DContainerLink.objects.get_or_create(source=sco,
+ destination=co)
+ clo.name = cl_d['name']
+ clo.save()
+ self._update_cc(ro, r_d)
- cc_d = {}
- if ('custom_config' in r_d):
- cc_d = r_d['custom_config']
- sorted_keys = [''] * len(cc_d.keys())
- for k in cc_d:
- ccc_d = cc_d[k]
- idx = ccc_d.get('index', 0)
- if (idx == 0):
- for i in range(len(sorted_keys)):
- if (sorted_keys[i] == ''):
- sorted_keys[i] = k
- break
- else:
- sorted_keys[idx-1] = k
- for k in sorted_keys:
- ccc_d = cc_d[k]
- cco, created = DCustomConfig.objects.get_or_create(
- rockon=ro, key=k,
- defaults={'description': ccc_d['description'], 'label': ccc_d['label']})
- if (not created):
- cco.description = ccc_d['description']
- cco.label = ccc_d['label']
- cco.save()
- def_val = ccc_d.get('default')
- if (def_val is not None):
- cco.val = def_val
- cco.save()
+
+ def _sorted_keys(self, cd):
+ sorted_keys = [''] * len(cd.keys())
+ for k in cd:
+ ccd = cd[k]
+ idx = ccd.get('index', 0)
+ if (idx == 0):
+ for i in range(len(sorted_keys)):
+ if (sorted_keys[i] == ''):
+ sorted_keys[i] = k
+ break
+ else:
+ sorted_keys[idx-1] = k
+ return sorted_keys
+
+ def _update_model(self, modelinst, ad):
+ for k,v in ad.iteritems():
+ setattr(modelinst, k, v)
+ modelinst.save()
+
+ def _update_cc(self, ro, r_d):
+ cc_d = r_d.get('custom_config', {})
+ for k in self._sorted_keys(cc_d):
+ ccc_d = cc_d[k]
+ defaults = {'description': ccc_d['description'],
+ 'label': ccc_d['label'], }
+ cco, created = DCustomConfig.objects.get_or_create(
+ rockon=ro, key=k, defaults=defaults)
+ if (not created): self._update_model(cco, defaults)
for cco in DCustomConfig.objects.filter(rockon=ro):
- if (cco.key not in cc_d):
- cco.delete()
+ if (cco.key not in cc_d): cco.delete()
+
+ def _update_env(self, co, c_d):
+ cc_d = c_d.get('environment', {})
+ for k in self._sorted_keys(cc_d):
+ ccc_d = cc_d[k]
+ defaults = {'description': ccc_d['description'],
+ 'label': ccc_d['label'], }
+ cco, created = DContainerEnv.objects.get_or_create(
+ container=co, key=k, defaults=defaults)
+ if (not created): self._update_model(cco, defaults)
+ for eo in DContainerEnv.objects.filter(container=co):
+ if (eo.key not in cc_d): eo.delete()
def _get_available(self, request):
msg = ('Network error while checking for updates. '
diff --git a/src/rockstor/storageadmin/views/rockon_environment.py b/src/rockstor/storageadmin/views/rockon_environment.py
new file mode 100644
index 000000000..24048a376
--- /dev/null
+++ b/src/rockstor/storageadmin/views/rockon_environment.py
@@ -0,0 +1,36 @@
+"""
+Copyright (c) 2012-2013 RockStor, Inc.
+This file is part of RockStor.
+
+RockStor is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+RockStor is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+"""
+
+from storageadmin.models import (RockOn, DContainer, DContainerEnv)
+from storageadmin.serializers import RockOnEnvironmentSerializer
+import rest_framework_custom as rfc
+from storageadmin.util import handle_exception
+
+
+class RockOnEnvironmentView(rfc.GenericView):
+ serializer_class = RockOnEnvironmentSerializer
+
+ def get_queryset(self, *args, **kwargs):
+ try:
+ rockon = RockOn.objects.get(id=self.kwargs['rid'])
+ except:
+ e_msg = ('Rock-on(%s) does not exist' % self.kwargs['rid'])
+ handle_exception(Exception(e_msg), self.request)
+
+ containers = DContainer.objects.filter(rockon=rockon)
+ return DContainerEnv.objects.filter(container__in=containers).order_by('id')
diff --git a/src/rockstor/storageadmin/views/rockon_helpers.py b/src/rockstor/storageadmin/views/rockon_helpers.py
index ed44720fd..2dabcb822 100644
--- a/src/rockstor/storageadmin/views/rockon_helpers.py
+++ b/src/rockstor/storageadmin/views/rockon_helpers.py
@@ -29,7 +29,7 @@
from system.services import service_status
from storageadmin.models import (RockOn, DContainer, DVolume, DPort,
DCustomConfig, Share, Disk, DContainerLink,
- ContainerOption)
+ ContainerOption, DContainerEnv)
from fs.btrfs import mount_share
from system.pkg_mgmt import install_pkg
from rockon_utils import container_status
@@ -183,15 +183,37 @@ def vol_ops(container):
ops_list.extend(['-v', '%s:%s' % (share_mnt, v.dest_dir)])
return ops_list
+def vol_owner_uid(container):
+ # If there are volumes, return the uid of the owner of the first volume.
+ vo = DVolume.objects.filter(container=container).first()
+ if (vo is None): return None
+ share_mnt = ('%s%s' % (settings.MNT_PT, vo.share.name))
+ return os.stat(share_mnt).st_uid
+
+def envars(container):
+ var_list = []
+ for e in DContainerEnv.objects.filter(container=container):
+ var_list.extend(['-e', '%s=%s' % (e.key, e.val)])
+ return var_list
+
def generic_install(rockon):
for c in DContainer.objects.filter(rockon=rockon).order_by('launch_order'):
+ rm_container(c.name)
cmd = list(DCMD2) + ['--name', c.name,]
cmd.extend(vol_ops(c))
+ if (c.uid is not None):
+ uid = c.uid
+ if (c.uid is -1):
+ uid = vol_owner_uid(c)
+ #@todo: what if the uid does not exist? Create a user with username=container-name?
+ cmd.extend(['-u', str(uid)])
cmd.extend(port_ops(c))
cmd.extend(container_ops(c))
+ cmd.extend(envars(c))
cmd.append(c.dimage.name)
run_command(cmd)
+
def openvpn_install(rockon):
#volume container
vol_co = DContainer.objects.get(rockon=rockon, launch_order=1)
@@ -214,23 +236,17 @@ def openvpn_install(rockon):
run_command(server_cmd)
-def transmission_install(rockon):
- co = DContainer.objects.get(rockon=rockon, launch_order=1)
- cmd = list(DCMD2) + ['--name', co.name]
- for cco in DCustomConfig.objects.filter(rockon=rockon):
- cmd.extend(['-e', '%s=%s' % (cco.key, cco.val)])
- cmd.extend(vol_ops(co))
- cmd.extend(port_ops(co))
- cmd.append(co.dimage.name)
- run_command(cmd)
-
-
def owncloud_install(rockon):
for c in DContainer.objects.filter(rockon=rockon).order_by('launch_order'):
+ rm_container(c.name)
cmd = list(DCMD2) + ['--name', c.name, ]
db_user = DCustomConfig.objects.get(rockon=rockon, key='db_user').val
db_pw = DCustomConfig.objects.get(rockon=rockon, key='db_pw').val
if (c.dimage.name == 'postgres'):
+ #change permissions on the db volume to 700
+ vo = DVolume.objects.get(container=c)
+ share_mnt = ('%s%s' % (settings.MNT_PT, vo.share.name))
+ run_command(['/usr/bin/chmod', '700', share_mnt])
cmd.extend(['-e', 'POSTGRES_USER=%s' % db_user, '-e',
'POSTGRES_PASSWORD=%s' % db_pw])
cmd.extend(port_ops(c))
diff --git a/src/rockstor/storageadmin/views/rockon_id.py b/src/rockstor/storageadmin/views/rockon_id.py
index e8b427715..336f482b0 100644
--- a/src/rockstor/storageadmin/views/rockon_id.py
+++ b/src/rockstor/storageadmin/views/rockon_id.py
@@ -21,7 +21,7 @@
from django.db import transaction
from django.db.models import Q
from storageadmin.models import (RockOn, DContainer, DVolume, Share, DPort,
- DCustomConfig)
+ DCustomConfig, DContainerEnv)
from storageadmin.serializers import RockOnSerializer
import rest_framework_custom as rfc
from storageadmin.util import handle_exception
@@ -82,6 +82,7 @@ def post(self, request, rid, command):
share_map = request.data.get('shares', {})
port_map = request.data.get('ports', {})
cc_map = request.data.get('cc', {})
+ env_map = request.data.get('environment', {})
containers = DContainer.objects.filter(rockon=rockon)
for co in containers:
for s in share_map.keys():
@@ -118,6 +119,13 @@ def post(self, request, rid, command):
cco = DCustomConfig.objects.get(rockon=rockon, key=c)
cco.val = cc_map[c]
cco.save()
+ for e in env_map.keys():
+ if (not DContainerEnv.objects.filter(container=co, key=e).exists()):
+ e_msg = ('Invalid environment variabled(%s)' % e)
+ handle_exception(Exception(e_msg), request)
+ ceo = DContainerEnv.objects.get(container=co, key=e)
+ ceo.val = env_map[e]
+ ceo.save()
install.async(rockon.id)
rockon.state = 'pending_install'
rockon.save()