Commit 9ab17d5f by Sulyok Gábor

Commit previous changes for Setty

parent 39a7ffc9
...@@ -17,13 +17,21 @@ ...@@ -17,13 +17,21 @@
from django.contrib import admin from django.contrib import admin
from .models import ( from .models import (
Element, Service,
ElementCategory,
ElementTemplate, ElementTemplate,
ElementConnection, ElementConnection,
Service, Machine,
NginxNode,
MySQLNode,
PostgreSQLNode
) )
admin.site.register(Element) admin.site.register(ElementCategory)
admin.site.register(ElementTemplate) admin.site.register(ElementTemplate)
admin.site.register(ElementConnection) admin.site.register(ElementConnection)
admin.site.register(Service) admin.site.register(Service)
admin.site.register(Machine)
admin.site.register(NginxNode)
admin.site.register(MySQLNode)
admin.site.register(PostgreSQLNode)
from .models import *
from django.core.exceptions import PermissionDenied
from django.db.models import Q
from django.db.models.loading import get_model
from saltstackhelper import *
import os
class SettyController:
salthelper = SaltStackHelper()
@staticmethod
def saveService( serviceId, serviceName, serviceNodes, machines, elementConnections ):
service = None
try:
service = Service.objects.get(id=serviceId)
except Service.DoesNotExist:
return JsonResponse( {'error': 'Service not found'})
service.name = serviceName
service.save()
#first check machine names
#validMachineNames = self.salthelper.getAllMinionsUngrouped()
Machine.objects.filter(service=service).delete()
for machineData in machines:
# if machineData["hostname"] in validMachineNames:
machineSaved = Machine(service=service)
machineSaved.fromDataDictionary( machineData )
machineSaved.save()
ServiceNode.objects.filter(service=service).delete()
for node in serviceNodes:
elementTemplateId = node["displayId"].split("_")[0]
elementTemplate = ElementTemplate.objects.get(id=elementTemplateId)
newNode = get_model('setty', elementTemplate.prototype ).clone()
newNode.service = service
newNode.fromDataDictionary( node )
newNode.save()
for elementConnection in elementConnections:
sourceId = elementConnection['sourceId']
targetId = elementConnection['targetId']
sourceEndpoint = elementConnection['sourceEndpoint']
targetEndpoint = elementConnection['targetEndpoint']
connectionParameters = elementConnection['parameters']
targetObject = Element.objects.get(
display_id=targetId)
sourceObject = Element.objects.get(
display_id=sourceId)
connectionObject = ElementConnection(
target=targetObject,
source=sourceObject,
target_endpoint=targetEndpoint,
source_endpoint=sourceEndpoint,
parameters=connectionParameters
)
connectionObject.save()
return {"serviceName": serviceName}
@staticmethod
def loadService(serviceId):
service = None
try:
service = Service.objects.get(id=serviceId)
except Service.DoesNotExist:
return JsonResponse({'error': 'Service not found'})
machineList = Machine.objects.filter(service=service)
serviceNodes = []
elementConnections = []
machines = []
for machine in machineList:
machines.append(machine.getDataDictionary())
serviveNodeList = ServiceNode.objects.filter(service=service)
elementConnectionList = ElementConnection.objects.filter(
Q(target__in=serviveNodeList) | Q(source__in=serviveNodeList))
for servideNode in serviveNodeList:
serviceNodes.append( servideNode.cast().getDataDictionary() )
for elementConnection in elementConnectionList:
elementConnections.append( elementConnection.getDataDictionary() )
return {'serviceName': service.name,
'elementConnections': elementConnections,
'serviceNodes': serviceNodes,
'machines': machines}
@staticmethod
def getInformation(elementTemplateId, hostname):
if elementTemplateId:
try:
elementTemplate = ElementTemplate.objects.get(
id=elementTemplateId)
model = get_model('setty', elementTemplate.prototype)
return model.getInformation()
except ElementTemplate.DoesNotExist:
return
except LookupError:
return
elif hostname:
return Machine.getInformation()
elif hostname and elementTemplateId:
raise PermissionDenied # TODO: something more meaningful
else:
raise PermissionDenied # TODO: something more meaningful
@staticmethod
def getMachineAvailableList(service_id, used_hostnames):
all_minions = SettyController.salthelper.getAllMinionsGrouped()
result = []
#TODO: filter out used ones
for item in all_minions["up"]:
result.append( {'hostname': item,
'hardware-info': SettyController.salthelper.getMinionBasicHardwareInfo( item ),
'status': 'up'} )
for item in all_minions["down"]:
result.append( {'hostname': item, 'status': 'down' })
return { 'machinedata': result }
@staticmethod
def addMachine(hostname):
try:
Machine.objects.get(hostname=hostname)
return {'error': 'already added or doesnt exists'}
except:
pass
if SettyController.salthelper.checkMinionExists(hostname):
machine = Machine.clone()
machine.hostname = hostname
return machine.getDataDictionary()
else:
return {'error': 'already added or doesnt exists'}
@staticmethod
def addServiceNode(elementTemplateId):
if elementTemplateId:
try:
elementTemplate = ElementTemplate.objects.get(id=elementTemplateId)
model = get_model('setty', elementTemplate.prototype )
return model.clone().getDataDictionary()
except ElementTemplate.DoesNotExist:
return {'error': 'lofaszka' }
except:
return {'error': 'valami nagyon el lett baszva'}
else:
return {'error': 'templateid'}
@staticmethod
def deploy(serviceId):
service = Service.objects.get(id=serviceId)
machines = Machine.objects.filter(service=service)
elementConnections = ElementConnection.objects.filter(
Q(target__in=machines) | Q(source__in=machines) )
firstLevelServiceNodes = []
#phase one: set the machine ptr in serviceNodes which can be accessed by
# connections from machines
for machine in machines:
for connection in elementConnections:
serviceNode = None
if connection.target.cast() == machine:
serviceNode = connection.source.cast()
serviceNode.setMachineForDeploy( machine )
elif connection.source.cast() == machine:
serviceNode = connection.target.cast()
serviceNode.setMachineForDeploy( machine )
else:
raise PermissionDenied
firstLevelServiceNodes.append( serviceNode )
#phase two: let the nodes create configurations recursively
configuratedNodes = list()
for serviceNode in firstLevelServiceNodes:
generatedNodes = serviceNode.generateConfigurationRecursively()
if isinstance( generatedNodes, list ):
configuratedNodes = configuratedNodes + generatedNodes
else:
configuratedNodes.append( generatedNodes )
#phase three: sort the nodes by deployment priority(lower the prio, later in the deployement)
configuratedNodes.sort(reverse=True)
#deploy the nodes
for node in configuratedNodes:
SettyController.salthelper.deploy( node.machine.hostname, node.generatedConfig )
return {'status': 'deployed'}
#cleanup the temporary data
''' for node in configuratedNodes:
node.deployCleanUp()'''
\ No newline at end of file
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import setty.storage
class Migration(migrations.Migration):
dependencies = [
('setty', '0012_auto_20160308_1432'),
]
operations = [
migrations.CreateModel(
name='ElementCategory',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50)),
('parent_category', models.ForeignKey(to='setty.ElementCategory', null=True)),
],
),
migrations.CreateModel(
name='Machine',
fields=[
('element_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='setty.Element')),
('hostname', models.TextField()),
('alias', models.CharField(max_length=50)),
('config_file', models.FileField(default=None, storage=setty.storage.OverwriteStorage(), upload_to=b'setty/machine_configs/')),
('description', models.TextField(default=b'')),
('status', models.CharField(max_length=1, choices=[(1, b'Running'), (2, b'Unreachable')])),
],
options={
'abstract': False,
},
bases=('setty.element',),
),
migrations.CreateModel(
name='ServiceNode',
fields=[
('element_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='setty.Element')),
('name', models.CharField(max_length=50)),
('config_file', models.FileField(default=None, storage=setty.storage.OverwriteStorage(), upload_to=b'setty/node_configs/')),
('description', models.TextField(default=b'')),
('machine', models.ForeignKey(to='setty.Machine')),
],
bases=('setty.element',),
),
migrations.RemoveField(
model_name='element',
name='parameters',
),
migrations.RemoveField(
model_name='element',
name='service',
),
migrations.RemoveField(
model_name='elementtemplate',
name='parameters',
),
migrations.AlterField(
model_name='service',
name='status',
field=models.CharField(default=1, max_length=1, choices=[(1, b'Draft'), (2, b'Deployed')]),
),
migrations.AddField(
model_name='machine',
name='service',
field=models.ForeignKey(related_name='service_id', to='setty.Service'),
),
migrations.AddField(
model_name='elementtemplate',
name='category',
field=models.ForeignKey(to='setty.ElementCategory', null=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('setty', '0013_saltstack_changes'),
]
operations = [
migrations.CreateModel(
name='NginxNode',
fields=[
('servicenode_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='setty.ServiceNode')),
('worker_connections', models.PositiveIntegerField()),
],
bases=('setty.servicenode',),
),
migrations.CreateModel(
name='WebServerNode',
fields=[
('servicenode_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='setty.ServiceNode')),
('useSSL', models.BooleanField(default=False)),
('listeningPort', models.PositiveIntegerField()),
],
bases=('setty.servicenode',),
),
migrations.RemoveField(
model_name='elementtemplate',
name='tags',
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('setty', '0014_auto_20160320_1724'),
]
operations = [
migrations.AlterField(
model_name='elementcategory',
name='parent_category',
field=models.ForeignKey(blank=True, to='setty.ElementCategory', null=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import setty.storage
class Migration(migrations.Migration):
dependencies = [
('setty', '0015_allow_blank_elementcategory_parent'),
]
operations = [
migrations.AddField(
model_name='elementtemplate',
name='prototype',
field=models.TextField(default=b'<SYNTAX ERROR>'),
),
migrations.AlterField(
model_name='elementtemplate',
name='compatibles',
field=models.ManyToManyField(related_name='compatibles_rel_+', to='setty.ElementTemplate', blank=True),
),
migrations.AlterField(
model_name='elementtemplate',
name='logo',
field=models.FileField(storage=setty.storage.OverwriteStorage(), upload_to=b'setty/', blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import setty.storage
class Migration(migrations.Migration):
dependencies = [
('setty', '0016_auto_20160320_1753'),
]
operations = [
migrations.RemoveField(
model_name='nginxnode',
name='servicenode_ptr',
),
migrations.AddField(
model_name='nginxnode',
name='webservernode_ptr',
field=models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, default=None, serialize=False, to='setty.WebServerNode'),
preserve_default=False,
),
migrations.AlterField(
model_name='elementtemplate',
name='logo',
field=models.FileField(storage=setty.storage.OverwriteStorage(), upload_to=b'setty/'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('setty', '0017_auto_20160320_1828'),
]
operations = [
migrations.RemoveField(
model_name='servicenode',
name='machine',
),
migrations.AddField(
model_name='servicenode',
name='service',
field=models.ForeignKey(default=None, to='setty.Service'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('setty', '0018_auto_20160420_1728'),
]
operations = [
migrations.AlterField(
model_name='servicenode',
name='service',
field=models.ForeignKey(related_name='node_service_id', default=None, to='setty.Service'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('setty', '0019_auto_20160420_2043'),
]
operations = [
migrations.AlterField(
model_name='servicenode',
name='service',
field=models.ForeignKey(default=None, to='setty.Service'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('setty', '0020_auto_20160420_2132'),
]
operations = [
migrations.AddField(
model_name='element',
name='real_type',
field=models.ForeignKey(default=None, editable=False, to='contenttypes.ContentType'),
),
]
...@@ -17,46 +17,101 @@ ...@@ -17,46 +17,101 @@
from django.db import models from django.db import models
from django.db.models import Model from django.db.models import Model
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User from django.contrib.auth.models import User
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from storage import OverwriteStorage from storage import OverwriteStorage
import os
# TODO: derive from object or keep the tricky base function calling?
# TODO: exceptions
SALTSTACK_STATE_FOLDER = "/srv/salt"
def replaceParameter(config, parameterToReplace, newValue):
configEdited = config.replace(parameterToReplace, str(newValue))
return configEdited
class Service(models.Model):
SERVICE_STATUS_CHOICES = ((1, 'Draft'),
(2, 'Deployed'))
class Service(Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
name = models.TextField(verbose_name="Name") name = models.TextField(verbose_name="Name")
status = models.CharField(max_length=50) status = models.CharField(
choices=SERVICE_STATUS_CHOICES, max_length=1, default=1)
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class ElementTemplate(Model): class ElementCategory(models.Model):
name = models.CharField(max_length=50)
parent_category = models.ForeignKey(
'self', on_delete=models.CASCADE, null=True, blank=True)
def __unicode__(self):
return self.name
class ElementTemplate(models.Model):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
logo = models.FileField(upload_to='setty/', storage=OverwriteStorage()) logo = models.FileField(upload_to='setty/', storage=OverwriteStorage())
description = models.TextField() description = models.TextField()
parameters = models.TextField() compatibles = models.ManyToManyField('self', blank=True)
compatibles = models.ManyToManyField('self') category = models.ForeignKey(
tags = TaggableManager(blank=True, verbose_name=_("tags")) ElementCategory, on_delete=models.CASCADE, null=True)
prototype = models.TextField(default="<SYNTAX ERROR>")
def __unicode__(self): def __unicode__(self):
return self.name return self.name
# http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982
# Super base class to prevent messing the code in the controller
# it saves the type info to DB, and when the objects are queried, the cast method returns the real class
# not the base
class Element(Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE) class InheritanceCastModel(models.Model):
parameters = models.TextField() real_type = models.ForeignKey(ContentType, editable=False, default=None)
def save(self, *args, **kwargs):
if not self.id:
self.real_type = self._get_real_type()
super(InheritanceCastModel, self).save(*args, **kwargs)
def _get_real_type(self):
return ContentType.objects.get_for_model(type(self))
def cast(self):
return self.real_type.get_object_for_this_type(pk=self.pk)
class Meta:
abstract = True
class Element(InheritanceCastModel):
display_id = models.TextField() display_id = models.TextField()
position_left = models.FloatField() position_left = models.FloatField()
position_top = models.FloatField() position_top = models.FloatField()
anchor_number = models.PositiveSmallIntegerField() anchor_number = models.PositiveSmallIntegerField()
def __unicode__(self): def getDisplayData(self):
return "%s (%s)" % (self.service.name, self.display_id) return {'displayId': self.display_id,
'positionLeft': self.position_left,
'positionTop': self.position_top,
'anchorNumber': self.anchor_number}
def setDisplayData(self, data):
self.display_id = data["displayId"]
self.position_left = data["positionLeft"]
self.position_top = data["positionTop"]
self.anchor_number = data["anchorNumber"]
class ElementConnection(Model):
class ElementConnection(models.Model):
target = models.ForeignKey( target = models.ForeignKey(
Element, Element,
related_name='target', related_name='target',
...@@ -70,4 +125,265 @@ class ElementConnection(Model): ...@@ -70,4 +125,265 @@ class ElementConnection(Model):
parameters = models.TextField() parameters = models.TextField()
def __unicode__(self): def __unicode__(self):
return "%s (%d)" % (self.target.service.name, self.id) return "%d" % self.id
def getDataDictionary(self):
return {'targetEndpoint': self.target_endpoint,
'sourceEndpoint': self.source_endpoint,
'parameters': self.parameters}
class Machine(Element): # As a real machine
MACHINE_STATUS_CHOICES = (
(1, 'Running'),
(2, 'Unreachable'))
service = models.ForeignKey(
Service, on_delete=models.CASCADE, related_name="service_id")
hostname = models.TextField(null=False) # also serves as salt-minion id
alias = models.CharField(max_length=50)
#config_file = models.FileField(default=None,upload_to='setty/machine_configs/', storage=OverwriteStorage())
description = models.TextField(default="")
status = models.CharField(choices=MACHINE_STATUS_CHOICES, max_length=1)
def __unicode__(self):
return "%s" % self.hostname
@staticmethod
def getInformation():
return {'hostname': hostname.get_internal_type(),
'alias': alias.get_internal_type(),
'description': description.get_internal_type()}
def getDataDictionary(self):
element_data = self.getDisplayData()
self_data = {'hostname': self.hostname,
'alias': self.alias,
'description': self.description}
element_data.update(self_data)
return element_data
def fromDataDictionary(self, data):
self.setDisplayData(data)
self.hostname = data["hostname"]
self.alias = data["alias"]
self.description = data["description"]
@staticmethod
def clone():
return Machine()
class ServiceNode(Element):
service = models.ForeignKey(
Service, on_delete=models.CASCADE, default=None)
name = models.CharField(max_length=50)
config_file = models.FileField(
default=None, upload_to='setty/node_configs/', storage=OverwriteStorage())
description = models.TextField(default="")
machine = None # for deploying
generatedConfig = None
def __unicode__(self):
return "%s" % self.name
def getDataDictionary(self):
element_data = self.getDisplayData()
self_data = {'name': self.name,
'description': self.description}
element_data.update(self_data)
return element_data
def fromDataDictionary(self, data):
self.setDisplayData(data)
self.name = data['name']
self.description = data['description']
@staticmethod
def getInformation():
return {'name': ServiceNode._meta.get_field('name').get_internal_type(),
'description': ServiceNode._meta.get_field('description').get_internal_type()}
@staticmethod
def clone():
raise PermissionDenied
def __cmp__(self, other):
return self.getDeploymentPriority(self).__cmp__(other.getDeploymentPriority(other))
# functions for deployement
def setMachineForDeploy(self, machine):
self.machine = machine
def getDeploymentPriority(self):
return 0
def generateConfigurationRecursively(self):
raise PermissionDenied
class WebServerNode(ServiceNode):
useSSL = models.BooleanField(default=False)
listeningPort = models.PositiveIntegerField()
def getDataDictionary(self):
element_data = ServiceNode.getDataDictionary(self)
self_data = {'useSSL': self.useSSL,
'listeningPort': self.listeningPort}
element_data.update(self_data)
return element_data
def fromDataDictionary(self, data):
ServiceNode.fromDataDictionary(self, data)
self.useSSL = data['useSSL']
self.listeningPort = data['listeningPort']
@staticmethod
def getInformation():
superInformation = ServiceNode.getInformation()
ownInformation = {'useSSL': WebServerNode._meta.get_field('useSSL').get_internal_type(),
'listeningPort': WebServerNode._meta.get_field('listeningPort').get_internal_type()}
ownInformation.update(superInformation)
return ownInformation
@staticmethod
def getDeploymentPriority(self):
return 10
def generateConfiguration(self, config=""):
config = replaceParameter(config, r"%%USE_SSL%%", self.useSSL)
config = replaceParameter(config,
r"%%LISTENING_PORT%%", self.listeningPort)
return config
class NginxNode(WebServerNode):
worker_connections = models.PositiveIntegerField()
def getDataDictionary(self):
element_data = WebServerNode.getDataDictionary(self)
self_data = {'worker_connections': self.worker_connections}
element_data.update(self_data)
return element_data
def fromDataDictionary(self, data):
WebServerNode.fromDataDictionary(self, data)
self.worker_connections = data['worker_connections']
@staticmethod
def getInformation():
superInformation = WebServerNode.getInformation()
ownInformation = {'worker_connections': NginxNode._meta.get_field(
'worker_connections').get_internal_type()}
ownInformation.update(superInformation)
return ownInformation
@staticmethod
def clone():
return NginxNode()
def generateConfigurationRecursively(self):
config = str()
exampleFilePath = os.path.join( SALTSTACK_STATE_FOLDER, "nginx.example" )
with open(exampleFilePath, 'r') as configFile:
config = configFile.read()
config = WebServerNode.generateConfiguration(self, config)
config = replaceParameter(config,
r"%%WORKER_CONNECTIONS%%", self.worker_connections)
self.generatedConfig = "nginx_%s.sls" % self.machine.hostname
with open(os.path.join(SALTSTACK_STATE_FOLDER, self.generatedConfig), 'w') as generatedConfigFile:
generatedConfigFile.write(config)
configuredNodes = []
configuredNodes.append(self)
return configuredNodes
class DatabaseNode(ServiceNode):
adminUserName = models.CharField(max_length=50)
adminPassword = models.CharField(max_length=50)
listeningPort = models.PositiveIntegerField()
def getDataDictionary(self):
element_data = ServiceNode.getDataDictionary(self)
self_data = {'admin_username': self.adminUserName,
'admin_password': self.adminPassword, 'listeningPort': self.listeningPort}
element_data.update(self_data)
return element_data
def fromDataDictionary(self, data):
ServiceNode.fromDataDictionary(self, data)
self.adminUserName = data['admin_username']
self.adminPassword = data['admin_password']
self.listeningPort = data['listeningPort']
@staticmethod
def getInformation():
superInformation = ServiceNode.getInformation()
ownInformation = {'admin_username': DatabaseNode._meta.get_field('adminUserName').get_internal_type(),
'admin_password': DatabaseNode._meta.get_field('adminPassword').get_internal_type(),
'listeningPort': DatabaseNode._meta.get_field('listeningPort').get_internal_type()}
ownInformation.update(superInformation)
return ownInformation
@staticmethod
def getDeploymentPriority(self):
return 10
def generateConfiguration(self, config=""):
config = replaceParameter(config,
r"%%ADMIN_USERNAME%%", self.adminUserName)
config = replaceParameter(config,
r"%%ADMIN_PASSWORD%%", self.adminUserName)
config = replaceParameter(config,
r'%%LISTENING_PORT%%', self.listeningPort)
return config
class PostgreSQLNode(DatabaseNode):
@staticmethod
def clone():
return PostgreSQLNode()
def generateConfigurationRecursively(self):
config = str()
exampleFilePath = os.path.join( SALTSTACK_STATE_FOLDER, "postgres.example" )
with open( exampleFilePath, 'r') as configFile:
config = configFile.read()
config = DatabaseNode.generateConfiguration(self, config)
self.generatedConfig = "postgres_%s.sls" % self.machine.hostname
with open(os.path.join(SALTSTACK_STATE_FOLDER, self.generatedConfig), 'w') as generatedConfigFile:
generatedConfigFile.write(config)
return self
class MySQLNode(DatabaseNode):
@staticmethod
def clone():
return MySQLNode()
def generateConfigurationRecursively(self):
config = str()
exampleFilePath = os.path.join( SALTSTACK_STATE_FOLDER, "mysql.example" )
with open(exampleFilePath, 'r') as configFile:
config = configFile.read()
config = DatabaseNode.generateConfiguration(self, config)
self.generatedConfig = "mysql_%s.sls" % self.machine.hostname
with open(os.path.join(SALTSTACK_STATE_FOLDER, self.generatedConfig), 'w') as generatedConfigFile:
generatedConfigFile.write(config)
return self
import salt.loader
import salt.config
import salt.runner
import salt.client
SALTSTACK_STATE_FOLDER = "/srv/salt"
class SaltStackHelper:
def __init__(self):
self.master_opts = salt.config.client_config('/etc/salt/master')
self.salt_runner = salt.runner.RunnerClient(self.master_opts)
self.salt_localclient = salt.client.LocalClient()
self.salt_caller = salt.client.Caller()
def getAllMinionsGrouped(self):
query_result = self.salt_runner.cmd('manage.status', []);
return query_result
def getAllMinionsUngrouped(self):
query_result = self.salt_runner.cmd('manage.status', []);
return query_result["up"] + query_result["down"]
def getRunningMinions(self):
return self.salt_runner.cmd('manage.up', []);
def getUnavailableMinions(self):
return self.salt_runner.cmd('manage.down', []);
def getMinionBasicHardwareInfo(self, hostname):
query_res = self.salt_localclient.cmd( hostname,'grains.items' );
if query_res:
return {
'CpuModel': query_res[hostname]['cpu_model'],
'CpuArch': query_res[hostname]['cpuarch'],
'TotalMemory': query_res[hostname]['mem_total'],
'OSDescription': query_res[hostname]['lsb_distrib_description'] }
return query_res
def checkMinionExists(self, hostname):
query_res = self.salt_localclient.cmd( hostname,'network.get_hostname' );
return query_res != None
def deploy(self, hostname, configFilePath ):
print configFilePath
self.salt_localclient.cmd(hostname, 'state.apply', [configFilePath.split('.')[0]] )
\ No newline at end of file

15.9 KB | W: | H:

15.9 KB | W: | H:

circle/setty/static/setty/apache.jpg
circle/setty/static/setty/apache.jpg
circle/setty/static/setty/apache.jpg
circle/setty/static/setty/apache.jpg
  • 2-up
  • Swipe
  • Onion skin

18.4 KB | W: | H:

18.4 KB | W: | H:

circle/setty/static/setty/lighttpd.jpg
circle/setty/static/setty/lighttpd.jpg
circle/setty/static/setty/lighttpd.jpg
circle/setty/static/setty/lighttpd.jpg
  • 2-up
  • Swipe
  • Onion skin

6.02 KB | W: | H:

6.02 KB | W: | H:

circle/setty/static/setty/nginx.jpg
circle/setty/static/setty/nginx.jpg
circle/setty/static/setty/nginx.jpg
circle/setty/static/setty/nginx.jpg
  • 2-up
  • Swipe
  • Onion skin
/* Settimng up csrf token, touch event and zoom options. */ /* Settimng up csrf token, touch event and zoom options. */
function getCookie(name) {
var cookieValue = null; function getCookie(name) {
if (document.cookie && document.cookie !== '') { var cookieValue = null;
var cookies = document.cookie.split(';'); if (document.cookie && document.cookie !== '') {
for (var i = 0; i < cookies.length; i++) { var cookies = document.cookie.split(';');
var cookie = jQuery.trim(cookies[i]); for (var i = 0; i < cookies.length; i++) {
if (cookie.substring(0, name.length + 1) == (name + '=')) { var cookie = jQuery.trim(cookies[i]);
cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); if (cookie.substring(0, name.length + 1) == (name + '=')) {
break; cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
} break;
} }
} }
return cookieValue; }
} return cookieValue;
}
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); function csrfSafeMethod(method) {
} return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
var csrftoken = getCookie('csrftoken');
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr, settings) { $.ajaxSetup({
if (!csrfSafeMethod(settings.type) && !this.crossDomain) { beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken); if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
} xhr.setRequestHeader("X-CSRFToken", csrftoken);
} }
}); }
});
/* Setty implementation starts here. */
/* Setty implementation starts here. */
jsPlumb.ready(function() {
var jsPlumbInstance = jsPlumb.getInstance({ jsPlumb.ready(function() {
DragOptions: { var jsPlumbInstance = jsPlumb.getInstance({
zIndex: 2000 DragOptions: {
}, zIndex: 2000
EndpointHoverStyle: { },
fillStyle: "green" EndpointHoverStyle: {
}, fillStyle: "green"
HoverPaintStyle: { },
strokeStyle: "green" HoverPaintStyle: {
}, strokeStyle: "green"
Container: "dropContainer" },
}); Container: "dropContainer"
var jsPlumbEndpoint = { });
endpoint: ["Dot", { var jsPlumbEndpoint = {
radius: 10 endpoint: ["Dot", {
}], radius: 10
paintStyle: { }],
fillStyle: "#9932cc" paintStyle: {
}, fillStyle: "#9932cc"
isSource: true, },
isTarget: true, isSource: true,
deleteEndpointsOnDetach: false, isTarget: true,
zIndex: 20, deleteEndpointsOnDetach: false,
connectorStyle: { zIndex: 20,
strokeStyle: "#9932cc", connectorStyle: {
lineWidth: 8 strokeStyle: "#9932cc",
}, lineWidth: 8
connector: ["Bezier", { },
curviness: 180 connector: ["Bezier", {
}], curviness: 180
maxConnections: 1, }],
dropOptions: { maxConnections: 1,
tolerance: "fit" dropOptions: {
} tolerance: "fit"
}; }
var elementConnections = []; };
var elementIndex = 0; var elementConnections = [];
var dragContainerScroll = 0; var elementIndex = 0;
var workspaceWidth = $("#dropContainer").width(); var dragContainerScroll = 0;
var workspaceHeight = $("#dropContainer").height(); var workspaceWidth = $("#dropContainer").width();
var workspaceHeight = $("#dropContainer").height();
var stackIndexer = 0;
var stackSize = 0; var stackIndexer = 0;
var objectStack = []; var stackSize = 0;
var undoStack = []; var objectStack = [];
var redoStack = []; var undoStack = [];
var clickEvent = 0; var redoStack = [];
var nextStepConstraint = 0; var clickEvent = 0;
var nextStepConstraint = 0;
/* Functions. */
/* Functions. */
setServiceStatus = function(status) {
if (status == "unsaved") { setServiceStatus = function(status) {
$("#serviceStatus").text(gettext("Unsaved")); if (status == "unsaved") {
} else { $("#serviceStatus").text("Unsaved");
$("#serviceStatus").empty(); }
} else {
}; $("#serviceStatus").empty();
}
addInfo = function(title, info, object, type) { };
mainDiv = $("<div>", {
class: "row", addInfo = function(title, info, type, object) {
html: $("<div>", { id = object.attr("id").split("_")[1];
class: "col-xs-12 text-center", $.post("", {
html: row = $("<h4>", { event: "getInformation",
html: title data: JSON.stringify({
}) "elementTemplateId": object.attr("id").split("_")[1],
}) "hostname": object.attr("hostname")})
}).add($("<div>", { }, function(result) {
class: "row", alert(result);
style: "margin-top: 16px", });
html: $("<div>", {
class: "col-xs-12 text-center", /*
html: row = $("<textarea>", { $("#informationContainer").empty();
class: "form-control",
style: "text-align: justify;", switch(type){
rows: "18", case "connection":
id: "infoInput", div =
disabled: !type, '<div class="row">' +
text: info '<div class="col-xs-12 text-center">' +
}) '<h4>' + title + '</h4>' +
}) '</div>' +
})); '</div>&nbsp;' +
controlDiv = $("<div>", { '<div class="row">' +
class: "row", '<div class="col-xs-12">' +
style: "margin-top: 16px", '<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
html: $("<div>", { '</div>' +
class: "col-xs-3 text-center", '</div>&nbsp;' +
html: $("<button>", { '<div class="row">' +
class: "btn btn-success btn-block", '<div class="col-xs-12 text-center">' +
id: "addEndpoint", '<button id="removeConnection" class="btn btn-info">Remove connection</button>' +
html: gettext("Add endpoint") '</div>' +
}) '</div>';
}).add($("<div>", { break;
class: "col-xs-3 text-center", case "element":
html: $("<button>", { div =
class: "btn btn-danger btn-block", '<div class="row">' +
id: "removeEndpoint", '<div class="col-xs-12 text-center">' +
html: gettext("Delete endpoint") '<h4>' + title + '</h4>' +
}) '</div>' +
})).add($("<div>", { '</div>&nbsp;' +
class: "col-xs-6 text-center", '<div class="row">' +
html: $("<button>", { '<div class="col-xs-12">' +
class: "btn btn-info btn-block", '<textarea class="form-control" rows="24" id="infoInput" placeholder="Config data"></textarea>' +
id: "removeElementFromWorkspace", '</div>' +
html: gettext("Remove from workspace") '</div>&nbsp;' +
}) '<div class="row text-center">' +
})) '<label>Endpoints</label>' +
}); '</div>' +
addElementDiv = $("<div>", { '<div class="row">' +
class: "row", '<div class="col-xs-6 text-center">' +
style: "margin-top: 16px", '<button id="addEndpoint" class="btn btn-success"><i class="fa fa-plus"></i></button>' +
html: $("<div>", { '</div>' +
class: "col-xs-12 text-center", '<div class="col-xs-6 text-center">' +
html: row = $("<button>", { '<button id="removeEndpoint" class="btn btn-danger"><i class="fa fa-minus"></i></button>' +
class: "btn btn-success", '</div>' +
id: "addElementToWorkspace", '</div>&nbsp;' +
html: gettext("Add to workspace") '<div class="row">' +
}) '<div class="col-xs-12 text-center">' +
}) '<button id="removeElementFromWorkspace" class="btn btn-info">Remove from workspace</button>' +
}); '</div>' +
'</div>';
$("#informationContainer").html(type?mainDiv.add(controlDiv):mainDiv.add(addElementDiv)); break;
case "elementTemplate":
$("#changeInformationDialog").modal('show'); div =
'<div class="row">' +
sharedObject = object; '<div class="col-xs-12 text-center">' +
}; '<h4>' + title + '</h4>' +
'</div>' +
updateConnections = function(connection, remove) { '</div>&nbsp;' +
if (!remove) { '<div class="row">' +
elementConnections.push(connection); '<div class="col-xs-12">' +
} else { '<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
index = -1; '</div>' +
for (var i = 0; i < elementConnections.length; i++) { '</div>&nbsp;' +
if (elementConnections[i] == connection) { '<div class="row">' +
index = i; '<div class="col-xs-12 text-center">' +
break; '<button id="addElementToWorkspace" class="btn btn-success">Add to workspace</button>' +
} '</div>' +
} '</div>';
if (index != -1) { break;
elementConnections.splice(index, 1); }*/
}
} // Here comes the ajax getInformation post.
// elementtemplateid vagy hostname
setServiceStatus("unsaved");
};
div = 0;
checkDuplicateConnection = function(connection) {
for (var i = 0; i < elementConnections.length; i++) { $("#informationContainer").append(div);
if (((elementConnections[i].targetId ==
connection.targetId && $("#infoInput").val(info);
elementConnections[i].sourceId ==
connection.sourceId) || $("#changeInformationDialog").modal('show');
(elementConnections[i].targetId ==
connection.sourceId && sharedObject = object;
elementConnections[i].sourceId == };
connection.targetId)) &&
elementConnections[i] != connection) { updateConnections = function(connection, remove) {
addMessage(gettext("Twofold connection is forbidden."), "danger"); if (!remove) {
return false; elementConnections.push(connection);
} } else {
} index = -1;
return true; for (var i = 0; i < elementConnections.length; i++) {
}; if (elementConnections[i] == connection) {
index = i;
checkCompatibility = function(sourceId, targetId) { break;
validTargets = $("#" + sourceId).attr("type").split(','); }
}
if (jQuery.inArray(targetId.split('_')[1], validTargets) == -1) { if (index != -1) {
addMessage(gettext("Connecting incompatible elements is forbidden."), "danger"); elementConnections.splice(index, 1);
return false; }
} }
return true;
}; setServiceStatus("unsaved");
};
checkSourceTargetEquality = function(connection) {
if (connection.targetId == connection.sourceId) { checkDuplicateConnection = function(connection) {
addMessage(gettext("Connecting element to itself is forbidden."), "danger"); for (var i = 0; i < elementConnections.length; i++) {
return false; if (((elementConnections[i].targetId ==
} connection.targetId &&
return true; elementConnections[i].sourceId ==
}; connection.sourceId) ||
(elementConnections[i].targetId ==
getAnchorCoordinate = function(rate) { connection.sourceId &&
x = Math.cos(2.0 * Math.PI * rate) / 2; elementConnections[i].sourceId ==
y = Math.sin(2.0 * Math.PI * rate) / 2; connection.targetId)) &&
dx = 0; elementConnections[i] != connection) {
dy = 0; addMessage(gettext("Twofold connection is forbidden."), "danger");
return false;
if (rate < 0.125) { }
x = 0.5; }
dx = 1; return true;
} else if (rate > 0.125 && rate < 0.375) { };
y = -0.5;
dy = -1; checkCompatibility = function(sourceId, targetId) {
} else if (rate > 0.375 && rate < 0.625) { validTargets = $("#" + sourceId).attr("type").split(',');
x = -0.5;
dx = -1; if (jQuery.inArray(targetId.split('_')[1], validTargets) == -1) {
} else if (rate > 0.625 && rate < 0.875) { addMessage(gettext("Connecting incompatible elements is forbidden."), "danger");
y = 0.5; return false;
dy = 1; }
} else if (rate > 0.875) { return true;
x = -0.5; };
dx = -1;
} else { checkSourceTargetEquality = function(connection) {
x = Math.sqrt(2) * Math.cos(2 * Math.PI * if (connection.targetId == connection.sourceId) {
rate) / 2; addMessage(gettext("Connecting element to itself is forbidden."), "danger");
y = Math.sqrt(2) * Math.sin(2 * Math.PI * return false;
rate) / 2; }
return true;
dx = Math.round(2 * x); };
}
return [y + 0.5, -x + 0.5, dy, -dx]; getAnchorCoordinate = function(rate) {
}; x = Math.cos(2.0 * Math.PI * rate) / 2;
y = Math.sin(2.0 * Math.PI * rate) / 2;
isConnected = function(anchorId) { dx = 0;
returnValue = false; dy = 0;
$.each(elementConnections, function(index) {
if (elementConnections[index].endpoints[0].getUuid() == anchorId || if (rate < 0.125) {
elementConnections[index].endpoints[1].getUuid() == anchorId) { x = 0.5;
returnValue = true; dx = 1;
return; } else if (rate > 0.125 && rate < 0.375) {
} y = -0.5;
}); dy = -1;
return returnValue; } else if (rate > 0.375 && rate < 0.625) {
}; x = -0.5;
dx = -1;
elementIsConnected = function(element) { } else if (rate > 0.625 && rate < 0.875) {
anchors = element.attr("anchors"); y = 0.5;
id = element.attr("id"); dy = 1;
} else if (rate > 0.875) {
for (i = 0; i < anchors; i++) { x = -0.5;
if (isConnected(i + "_" + id)) { dx = -1;
return true; } else {
} x = Math.sqrt(2) * Math.cos(2 * Math.PI *
} rate) / 2;
y = Math.sqrt(2) * Math.sin(2 * Math.PI *
return false; rate) / 2;
};
dx = Math.round(2 * x);
getConnectionparamAndAnchor = function(anchorId) { }
parameters = ""; return [y + 0.5, -x + 0.5, dy, -dx];
otherAnchor = ""; };
$.each(elementConnections, function(index) { isConnected = function(anchorId) {
if (elementConnections[index].endpoints[0].getUuid() == anchorId) { returnValue = false;
parameters = elementConnections[index].parameters; $.each(elementConnections, function(index) {
otherAnchor = elementConnections[index].endpoints[1].getUuid(); if (elementConnections[index].endpoints[0].getUuid() == anchorId ||
return; elementConnections[index].endpoints[1].getUuid() == anchorId) {
} returnValue = true;
return;
if (elementConnections[index].endpoints[1].getUuid() == anchorId) { }
parameters = elementConnections[index].parameters; });
otherAnchor = elementConnections[index].endpoints[0].getUuid(); return returnValue;
return; };
}
}); elementIsConnected = function(element) {
anchors = element.attr("anchors");
return [otherAnchor, parameters]; id = element.attr("id");
};
for(i=0;i<anchors;i++)
addEndpoint = function(element) { {
anchors = element.attr("anchors"); if(isConnected(i + "_" + id))
{
if (anchors == 8) return 1; return true;
}
anchors++; }
jsPlumbInstance.addEndpoint(document.getElementById(element.attr("id")), { return false;
uuid: (anchors - 1) + "_" + element.attr("id") };
},
jsPlumbEndpoint); getConnectionparamAndAnchor = function(anchorId) {
parameters = "";
for (i = 0; i < anchors; i++) { otherAnchor = "";
jsPlumbInstance.getEndpoint(i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
} $.each(elementConnections, function(index) {
if (elementConnections[index].endpoints[0].getUuid() == anchorId) {
element.attr("anchors", anchors); parameters = elementConnections[index].parameters;
otherAnchor = elementConnections[index].endpoints[1].getUuid();
jsPlumbInstance.repaintEverything(); return;
}
return 0;
}; if (elementConnections[index].endpoints[1].getUuid() == anchorId) {
parameters = elementConnections[index].parameters;
removeEndoint = function(element) { otherAnchor = elementConnections[index].endpoints[0].getUuid();
anchors = element.attr("anchors"); return;
}
if (anchors == 4) return 1; });
i = --anchors; return [otherAnchor, parameters];
};
while (isConnected(i + "_" + element.attr("id")) && i >= 0) i--;
addEndpoint = function(element) {
if (i == -1) { anchors = element.attr("anchors");
addMessage(gettext("Removing anchors is obstructed."), "danger");
return; if (anchors == 8) return;
} else if (i == anchors) {
jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(anchors + "_" + element.attr("id"))); anchors++;
} else {
newId = i + "_" + element.attr("id"); jsPlumbInstance.addEndpoint(document.getElementById(element.attr("id")), {
oldId = anchors + "_" + element.attr("id"); uuid: (anchors - 1) + "_" + element.attr("id")
},
data = getConnectionparamAndAnchor(oldId); jsPlumbEndpoint);
data.splice(0, 0, newId);
for (i = 0; i < anchors; i++) {
jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(oldId)); jsPlumbInstance.getEndpoint(i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
}
connectEndpoints(data);
} element.attr("anchors", anchors);
for (i = 0; i < anchors; i++) jsPlumbInstance.getEndpoint( jsPlumbInstance.repaintEverything();
i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors))); };
element.attr("anchors", anchors); removeEndoint = function(element) {
anchors = element.attr("anchors");
jsPlumbInstance.repaintEverything();
if (anchors == 4) return;
return 0;
}; i = --anchors;
connectEndpoints = function(data) { while (isConnected(i + "_" + element.attr("id")) && i >= 0) i--;
connectionObject =
jsPlumbInstance.connect({ if (i == -1) {
uuids: [data[0], data[1]] addMessage(gettext("Removing anchors is obstructed."), "danger");
}); return;
} else if (i == anchors) {
connectionObject.parameters = data[2]; jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(anchors + "_" + element.attr("id")));
} else {
setServiceStatus("unsaved"); newId = i + "_" + element.attr("id");
}; oldId = anchors + "_" + element.attr("id");
disconnectEndpoints = function(data) { data = getConnectionparamAndAnchor(oldId);
for (var i = 0; i < elementConnections.length; i++) { data.splice(0, 0, newId);
if (elementConnections[i].endpoints[0].getUuid() == data[0] &&
elementConnections[i].endpoints[1].getUuid() == data[1]) { jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(oldId));
jsPlumbInstance.detach(elementConnections[i]);
return; connectEndpoints(data);
} }
}
return; for (i = 0; i < anchors; i++) jsPlumbInstance.getEndpoint(
}; i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
addElement = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) { element.attr("anchors", anchors);
newInstance = "";
jsPlumbInstance.repaintEverything();
if (typeof idOrInstance != "string") { };
newInstance = idOrInstance;
endpoints = newInstance.attr("anchors"); connectEndpoints = function(data) {
newInstance.attr("anchors", 0); connectionObject =
} else { jsPlumbInstance.connect({
newInstance = $('#' + idOrInstance) source: data[0],
.clone() target: data[1]
.prop("id", newId) });
.prop("title", "Right click to delete")
.removeClass() connectionObject.parameters = data[2];
.addClass("element")
.attr("anchors", 0) setServiceStatus("unsaved");
.attr("parameters", parameters) };
.css("top", newPositionY)
.css("left", newPositionX); disconnectEndpoints = function(data) {
} for (var i = 0; i < elementConnections.length; i++) {
if (elementConnections[i].endpoints[0].getUuid() == data[0] &&
$("#dropContainer").append(newInstance); elementConnections[i].endpoints[1].getUuid() == data[1]) {
jsPlumbInstance.detach(elementConnections[i]);
for (i = 0; i <= endpoints; i++) { return;
addEndpoint(newInstance); }
} }
return;
jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), { };
containment: $("#dropContainer")
}); addElement = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) {
newInstance = "";
setServiceStatus("unsaved");
if (typeof idOrInstance != "string") {
jsPlumbInstance.repaintEverything(); newInstance = idOrInstance;
endpoints = newInstance.attr("anchomNumber");
return newInstance; newInstance.attr("anchors", 0);
}; } else {
newInstance = $('#' + idOrInstance)
removeElement = function(object) { .clone()
jsPlumbInstance.detachAllConnections(object); .prop("id", newId)
jsPlumbInstance.remove(object.attr("id")); .prop("title", "Right click to delete")
}; .removeClass()
.addClass("element")
.attr("anchors", 0)
/* Registering events using JsPlumb. */ .attr("parameters", parameters)
.css("top", newPositionY)
jsPlumbInstance.bind("connection", function(info) { .css("left", newPositionX);
updateConnections(info.connection); }
info.connection.parameters = "";
$("#dropContainer").append(newInstance);
if (clickEvent === 0) {
undoStack.splice(stackIndexer, 0, disconnectEndpoints); for (i = 0; i <= endpoints; i++) {
redoStack.splice(stackIndexer, 0, connectEndpoints); addEndpoint(newInstance);
connectionArray = []; }
connectionArray.push(info.connection.endpoints[0].getUuid(),
info.connection.endpoints[1].getUuid(), jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
info.connection.parameters); containment: $("#dropContainer")
objectStack.splice(stackIndexer, 0, connectionArray); });
stackIndexer++;
stackSize++; setServiceStatus("unsaved");
}
}); jsPlumbInstance.repaintEverything();
jsPlumbInstance.bind("beforeDrop", function(info) { return newInstance;
return checkDuplicateConnection(info.connection) && };
checkSourceTargetEquality(info.connection) && addMachine = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) {
checkCompatibility(info.connection.sourceId, info.connection.targetId); newInstance = "";
});
newInstance = $('<div>')
jsPlumbInstance.bind("connectionDetached", function(info) { .prop("id", newId)
updateConnections(info.connection, true); .prop("title", "Right click to delete")
.removeClass()
if (clickEvent === 0) { .addClass("element")
undoStack.splice(stackIndexer, 0, connectEndpoints); .attr("anchors", 0)
redoStack.splice(stackIndexer, 0, disconnectEndpoints); .attr("parameters", parameters)
connectionArray = []; .css("top", newPositionY)
connectionArray.push(info.connection.endpoints[0].getUuid(), .css("left", newPositionX);
info.connection.endpoints[1].getUuid(),
info.connection.parameters); $("#dropContainer").append(newInstance);
objectStack.splice(stackIndexer, 0, connectionArray);
stackIndexer++; for (i = 0; i <= endpoints; i++) {
stackSize++; addEndpoint(newInstance);
} }
});
jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
jsPlumbInstance.bind("connectionMoved", function(info) { containment: $("#dropContainer")
updateConnections(info.connection, true); });
});
setServiceStatus("unsaved");
jsPlumbInstance.bind("contextmenu", function(info) {
jsPlumbInstance.detach(info); jsPlumbInstance.repaintEverything();
});
return newInstance;
jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), { }
containment: $("#dropContainer") removeElement = function(object) {
}); jsPlumbInstance.detachAllConnections(object);
jsPlumbInstance.remove(object.attr("id"));
};
/* Registering events using JQuery. */
$('body').on('click', '.elementTemplate', function() { /* Registering events using JsPlumb. */
addElement($(this).attr("id"),
(++elementIndex) + "_" + $(this).attr("id"), jsPlumbInstance.bind("connection", function(info) {
(elementIndex % 21) * 30, 4, "", updateConnections(info.connection);
(elementIndex % 21) * 30); info.connection.parameters = "";
undoStack.splice(stackIndexer, 0, removeElement); if (clickEvent === 0) {
redoStack.splice(stackIndexer, 0, addElement); undoStack.splice(stackIndexer, 0, disconnectEndpoints);
objectStack.splice(stackIndexer, 0, newInstance); redoStack.splice(stackIndexer, 0, connectEndpoints);
stackSize++; connectionArray = [];
stackIndexer++; connectionArray.push(info.connection.endpoints[0].getUuid(),
}); info.connection.endpoints[1].getUuid(),
info.connection.parameters);
$('body').on('dblclick', '.element', function() { objectStack.splice(stackIndexer, 0, connectionArray);
element = $(this); stackIndexer++;
element.addClass("elementSelected"); stackSize++;
addInfo(element.attr("alt"), }
element.attr("parameters"), });
element, 1);
$(document).scrollTop(0); jsPlumbInstance.bind("beforeDrop", function(info) {
}); return checkDuplicateConnection(info.connection) &&
checkSourceTargetEquality(info.connection) &&
$('body').on('contextmenu', '.element', function(event) { checkCompatibility(info.connection.sourceId, info.connection.targetId);
setServiceStatus("unsaved"); });
removeElement($(this));
jsPlumbInstance.bind("connectionDetached", function(info) {
undoStack.splice(stackIndexer, 0, addElement); updateConnections(info.connection, true);
redoStack.splice(stackIndexer, 0, removeElement);
objectStack.splice(stackIndexer, 0, $(this)); if (clickEvent === 0) {
undoStack.splice(stackIndexer, 0, connectEndpoints);
nextStepConstraint = 0; redoStack.splice(stackIndexer, 0, disconnectEndpoints);
stackSize++; connectionArray = [];
stackIndexer++; connectionArray.push(info.connection.endpoints[0].getUuid(),
}); info.connection.endpoints[1].getUuid(),
info.connection.parameters);
$('body').on('keyup', '#infoInput', function() { objectStack.splice(stackIndexer, 0, connectionArray);
setServiceStatus("unsaved"); stackIndexer++;
newParams = $("#infoInput").val(); stackSize++;
}
sharedObject.attr("parameters", newParams); });
});
jsPlumbInstance.bind("connectionMoved", function(info) {
$('body').on('click', '#addEndpoint', function() { updateConnections(info.connection, true);
setServiceStatus("unsaved"); });
if(addEndpoint(sharedObject)) return;
undoStack.splice(stackIndexer, 0, removeEndoint); jsPlumbInstance.bind("contextmenu", function(info) {
redoStack.splice(stackIndexer, 0, addEndpoint); jsPlumbInstance.detach(info);
objectStack.splice(stackIndexer, 0, sharedObject); });
stackIndexer++;
stackSize++; jsPlumbInstance.bind("dblclick", function(info) {
}); info.setPaintStyle({strokeStyle:"red", lineWidth: 8});
addInfo($("#" + info.sourceId.split('_')[1]).attr("alt") + ' - ' + $("#" + info.targetId.split('_')[1]).attr("alt"),
$('body').on('click', '#removeEndpoint', function() { info.parameters,
setServiceStatus("unsaved"); "connection",
if(removeEndoint(sharedObject)) return; info);
undoStack.splice(stackIndexer, 0, addEndpoint); });
redoStack.splice(stackIndexer, 0, removeEndoint);
objectStack.splice(stackIndexer, 0, sharedObject); jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
stackIndexer++; containment: $("#dropContainer")
stackSize++; });
});
$('body').on('click', '#removeElementFromWorkspace', function() { /* Registering events using JQuery. */
setServiceStatus("unsaved");
removeElement(sharedObject); $('body').on('click', '.elementTemplate', function() {
addElement($(this).attr("id"),
undoStack.splice(stackIndexer, 0, addElement); (++elementIndex) + "_" + $(this).attr("id"),
redoStack.splice(stackIndexer, 0, removeElement); (elementIndex % 21) * 30, 4, "",
objectStack.splice(stackIndexer, 0, sharedObject); (elementIndex % 21) * 30);
stackSize++;
stackIndexer++; undoStack.splice(stackIndexer, 0, removeElement);
redoStack.splice(stackIndexer, 0, addElement);
$("#changeInformationDialog").modal('hide'); objectStack.splice(stackIndexer, 0, newInstance);
}); stackSize++;
stackIndexer++;
$('body').on('click', '#removeConnection', function() { });
jsPlumbInstance.detach(sharedObject);
}); $('body').on('dblclick', '.element', function() {
element = $(this);
$('body').on('click', '#addElementToWorkspace', function() { element.addClass("elementSelected");
newInstance = addElement(sharedObject.attr("id"), addInfo(element.attr("alt"),
(++elementIndex) + "_" + sharedObject.attr("id"), element.attr("parameters"),
(elementIndex % 21) * 30, 4, "", "element", element);
(elementIndex % 21) * 30); $(document).scrollTop(0);
});
undoStack.splice(stackIndexer, 0, removeElement);
redoStack.splice(stackIndexer, 0, addElement); $('body').on('contextmenu', '.element', function(event) {
objectStack.splice(stackIndexer, 0, newInstance); setServiceStatus("unsaved");
stackSize++; removeElement($(this));
stackIndexer++;
}); undoStack.splice(stackIndexer, 0, addElement);
redoStack.splice(stackIndexer, 0, removeElement);
$('body').on('click', '#clearService', function() { objectStack.splice(stackIndexer, 0, $(this));
//Todo
setServiceStatus("unsaved"); nextStepConstraint = 0;
stackSize++;
elementIndex = 0; stackIndexer++;
}); });
$('body').on('click', '#undoMovement', function() { $('body').on('click', '#closeInfoPanel', function() {
if (stackIndexer < 1) return; $('#informationPanel').hide();
stackIndexer--; $('#dragPanel').show();
clickEvent = 1; });
object = objectStack[stackIndexer];
undoStack[stackIndexer](object); $('body').on('keyUp', '#infoInput', function() {
clickEvent = 0; setServiceStatus("unsaved");
}); newParams = $("#infoInput").val();
$('body').on('click', '#redoMovement', function() { if (type == "connection") object.parameters = newParams;
if (stackIndexer >= stackSize) return; if (type == "element") object.attr("parameters", newParams);
clickEvent = 1; });
object = objectStack[stackIndexer];
redoStack[stackIndexer](object); $('body').on('click', '#addEndpoint', function() {
stackIndexer++; addEndpoint(sharedObject);
clickEvent = 0; undoStack.splice(stackIndexer, 0, removeEndoint);
}); redoStack.splice(stackIndexer, 0, addEndpoint);
objectStack.splice(stackIndexer, 0, sharedObject);
$('body').on('click', '#addMachineDialog', function() { stackIndexer++;
// Here comes the ajax post of getting machines stackSize++;
}); });
$('body').on('click', '.elementTemplateInfo', function() { $('body').on('click', '#removeEndpoint', function() {
id = $(this).attr("element"); removeEndoint(sharedObject);
addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), $("#" + id), 0); undoStack.splice(stackIndexer, 0, addEndpoint);
}); redoStack.splice(stackIndexer, 0, removeEndoint);
objectStack.splice(stackIndexer, 0, sharedObject);
$('body').on('click', '#serviceName', function() { stackIndexer++;
$('#serviceName').hide(); stackSize++;
$("#serviceNameEdit").css("display", "inline").val($(this).text()).select(); });
$("#serviceNameSave").css("display", "inline");
setServiceStatus("unsaved"); $('body').on('click', '#removeElementFromWorkspace', function() {
}); setServiceStatus("unsaved");
removeElement(sharedObject);
$('body').on('click', '#serviceNameSave', function() {
$('#serviceNameEdit').hide(); undoStack.splice(stackIndexer, 0, addElement);
$(this).hide(); redoStack.splice(stackIndexer, 0, removeElement);
$("#serviceName").show().text($('#serviceNameEdit').val()); objectStack.splice(stackIndexer, 0, sharedObject);
}); stackSize++;
stackIndexer++;
$('body').on('click', '#dragContainerScrollUp', function() { });
scrollContainer(-1);
}); $('body').on('click', '#removeConnection', function() {
jsPlumbInstance.detach(sharedObject);
$('body').on('click', '#dragContainerScrollDown', function() { });
scrollContainer(1);
}); $('body').on('click', '#addElementToWorkspace', function() {
newInstance = addElement(sharedObject.attr("id"),
$('body').on('hide.bs.modal', '#changeInformationDialog', function() { (++elementIndex) + "_" + sharedObject.attr("id"),
$('.element').removeClass('elementSelected'); (elementIndex % 21) * 30, 4, "",
}); (elementIndex % 21) * 30);
$('body').on('keyup', '#searchElementTemplate', function() { undoStack.splice(stackIndexer, 0, removeElement);
$(".elementTemplate").each(function() { redoStack.splice(stackIndexer, 0, addElement);
$(this).parent().parent().hide(); objectStack.splice(stackIndexer, 0, newInstance);
if ($(this).attr("alt").toLowerCase().indexOf($("#searchElementTemplateInput").val().toLowerCase()) >= 0) stackSize++;
$(this).parent().parent().show(); stackIndexer++;
}); });
});
$('body').on('click', '#clearService', function() {
$('body').on('mousewheel DOMMouseScroll onmousewheel', function(event) { jsPlumbInstance.remove("element");
var e = window.event || event; setServiceStatus("unsaved");
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
elementIndex = 0;
$('body').addClass("noScroll"); });
dragContainerScroll -= delta; $('body').on('click', '#undoMovement', function() {
if (stackIndexer < 1) return;
if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--; stackIndexer--;
if (dragContainerScroll == -1) dragContainerScroll++; clickEvent = 1;
object = objectStack[stackIndexer];
$("#dragContainer").scrollTop( undoStack[stackIndexer](object);
dragContainerScroll * $("#elementTemplatePanel").height() clickEvent = 0;
); });
$('body').removeClass("noScroll"); $('body').on('click', '#redoMovement', function() {
}); if (stackIndexer >= stackSize) return;
clickEvent = 1;
$(document).on('keydown', function(e) { object = objectStack[stackIndexer];
var eventObject = window.event ? event : e; redoStack[stackIndexer](object);
stackIndexer++;
// Undo (CTRL + Z) clickEvent = 0;
if (eventObject.keyCode == 90 && eventObject.ctrlKey) { });
eventObject.preventDefault();
$('#undoMovement').click(); $('body').on('click', '#addMachineDialog', function() {
} // Here comes the ajax post of getMachineAvailableList
// posting usedhostnames
// Redo (CTRL + Y) //
if (eventObject.keyCode == 89 && eventObject.ctrlKey) { //
eventObject.preventDefault(); // after it, appending obtained content to addmachinedialogbody
$('#redoMovement').click(); });
}
$('body').on('click', '.elementTemplateInfo', function() {
// Add element (CTRL + A) id = $(this).attr("element");
if (eventObject.keyCode == 65 && eventObject.ctrlKey) { addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), "elementTemplate", $("#" + id));
eventObject.preventDefault(); });
$('#showAddElementDialog').click();
} $('body').on('click', '#serviceName', function() {
$('#serviceName').hide();
// Clean (CTRL + C) $("#serviceNameEdit").css("display", "inline").val($(this).text()).select();
if (eventObject.keyCode == 67 && eventObject.ctrlKey) { $("#serviceNameSave").css("display", "inline");
eventObject.preventDefault(); setServiceStatus("unsaved");
$('#clearService').click(); });
}
$('body').on('click', '#serviceNameSave', function() {
// Save (CTRL + S) $('#serviceNameEdit').hide();
if (eventObject.keyCode == 83 && eventObject.ctrlKey) { $(this).hide();
eventObject.preventDefault(); $("#serviceName").show().text($('#serviceNameEdit').val());
$('#saveService').click(); });
}
$('body').on('click', '#dragContainerScrollUp', function() {
// Delete (CTRL + D) scrollContainer(-1);
if (eventObject.keyCode == 68 && eventObject.ctrlKey) { });
eventObject.preventDefault();
$('#deleteService').click(); $('body').on('click', '#dragContainerScrollDown', function() {
} scrollContainer(1);
});
// Close dialog (ESC)
if (eventObject.keyCode == 27) { $('body').on('hide.bs.modal', '#changeInformationDialog', function () {
eventObject.preventDefault(); $('.element').removeClass('elementSelected');
$("#changeInformationDialog").modal('hide'); jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8});
$("#addElementDialog").modal('hide'); });
}
}); $('body').on('keyup', '#searchElementTemplate', function() {
$(".elementTemplate").each(function() {
$(window).on('resize', function() { $(this).parent().parent().hide();
$(".element").each(function() { if ($(this).attr("alt").toLowerCase().indexOf($("#searchElementTemplateInput").val().toLowerCase()) >= 0)
rate = ($(this).position().left) / workspaceWidth; $(this).parent().parent().show();
left = rate * ($("#dropContainer").width()); });
$(this).css("left", left); });
});
workspaceWidth = $("#dropContainer").width(); $('body').on('mousewheel DOMMouseScroll onmousewheel', function(event) {
jsPlumbInstance.repaintEverything(); var e = window.event || event;
}); var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
$('body').addClass("noScroll");
/* Registering events concerning persistence. */
dragContainerScroll -= delta;
$('body').on('click', '#saveService', function() {
serviceName = $("#serviceName").text(); if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--;
connectionSet = []; if (dragContainerScroll == -1) dragContainerScroll++;
instanceSet = [];
$("#dragContainer").scrollTop(
$.each(elementConnections, function(index) { dragContainerScroll * $("#elementTemplatePanel").height()
connectionSet.push({ );
"sourceId": elementConnections[index].sourceId,
"sourceEndpoint": elementConnections[index].endpoints[0].getUuid(), $('body').removeClass("noScroll");
"targetId": elementConnections[index].targetId, });
"targetEndpoint": elementConnections[index].endpoints[1].getUuid(),
"parameters": elementConnections[index].parameters $(document).on('keydown', function(e) {
}); var eventObject = window.event ? event : e;
});
// Undo (CTRL + Z)
$.each($(".element"), function() { if (eventObject.keyCode == 90 && eventObject.ctrlKey)
instanceSet.push({ {
"displayId": $(this).prop("id"), eventObject.preventDefault();
"positionLeft": $(this).position().left / workspaceWidth, $('#undoMovement').click();
"positionTop": $(this).position().top / workspaceHeight, }
"anchorNumber": $(this).attr("anchors"),
"parameters": $(this).attr("parameters") // Redo (CTRL + Y)
}); if (eventObject.keyCode == 89 && eventObject.ctrlKey)
}); {
eventObject.preventDefault();
$.post("", { $('#redoMovement').click();
event: "saveService", }
data: JSON.stringify({
"serviceName": serviceName, // Add element (CTRL + A)
"elementConnections": connectionSet, if (eventObject.keyCode == 65 && eventObject.ctrlKey)
"elements": instanceSet {
}) eventObject.preventDefault();
}, function(result) { $('#showAddElementDialog').click();
addMessage(result.serviceName + gettext(" saved successfully."), "success"); }
setServiceStatus("saved");
}); // Clean (CTRL + C)
}); if (eventObject.keyCode == 67 && eventObject.ctrlKey)
{
$(document).ready(function() { eventObject.preventDefault();
if (!$("#dropContainer").length) return; // Protection for not posting sites that differ from setty sites. $('#clearService').click();
$.post("", { }
event: "loadService"
}, function(result) { // Save (CTRL + S)
$("#serviceName").text(result.serviceName); if (eventObject.keyCode == 83 && eventObject.ctrlKey)
{
$.each(result.elements, function(i, element) { eventObject.preventDefault();
addElement(element.displayId.split('_')[1], $('#saveService').click();
element.displayId, }
(element.positionTop * workspaceHeight) + "px",
element.anchorNumber, // Delete (CTRL + D)
element.parameters, if (eventObject.keyCode == 68 && eventObject.ctrlKey)
(element.positionLeft * workspaceWidth) + "px"); {
if (elementIndex < element.displayId.split('_')[0]) eventObject.preventDefault();
elementIndex = element.displayId.split('_')[0]; $('#deleteService').click();
elementIndex++; }
}); });
clickEvent = 1; $(window).on('resize', function() {
$.each(result.elementConnections, $(".element").each(function() {
function(i, connection) { rate = ($(this).position().left)/workspaceWidth;
connectEndpoints([connection.sourceEndpoint, connection.targetEndpoint, connection.parameters]); left = rate*($("#dropContainer").width());
}); $(this).css("left", left);
clickEvent = 0; });
setServiceStatus("saved"); workspaceWidth = $("#dropContainer").width();
}); jsPlumbInstance.repaintEverything();
}); });
});
/* Registering events concerning persistence. */
$('body').on('click', '#saveService', function() {
serviceName = $("#serviceName").text();
connectionSet = [];
instanceSet = [];
$.each(elementConnections, function(index) {
connectionSet.push({
"sourceId": elementConnections[index].sourceId,
"sourceEndpoint": elementConnections[index].endpoints[0].getUuid(),
"targetId": elementConnections[index].targetId,
"targetEndpoint": elementConnections[index].endpoints[1].getUuid(),
"parameters": elementConnections[index].parameters});
});
$.each($(".element"), function() {
instanceSet.push({
"displayId": $(this).prop("id"),
"positionLeft": $(this).position().left/workspaceWidth,
"positionTop": $(this).position().top/workspaceHeight,
"anchorNumber": $(this).attr("anchors"),
"parameters": $(this).attr("parameters")});
});
$.post("", {
event: "saveService",
data: JSON.stringify({
"serviceName": serviceName,
"elementConnections": connectionSet,
"elements": instanceSet,
"machines": []}) //TODO: Dani: add machines here
}, function(result) {
addMessage(result.serviceName + gettext(" saved successfully."),"success");
setServiceStatus("saved");
});
});
$(document).ready(function() {
if(!$("#dropContainer").length)
return;
$.post("", {
event: "loadService"
}, function(result) {
$("#serviceName").text(result.serviceName);
$.each(result.serviceNodes, function(i, element) {
addElement(element.displayId.split('_')[1],
element.displayId,
(element.positionTop*workspaceHeight) + "px",
element.anchorNumber,
element.parameters,
(element.positionLeft*workspaceWidth) + "px");
if (elementIndex < element.displayId.split('_')[0])
elementIndex = element.displayId.split('_')[0];
elementIndex++;
});
$.each(result.machines, function(i, element) {
addMachine(element.displayId.split('_')[1],
element.displayId,
(element.positionTop*workspaceHeight) + "px",
element.anchorNumber,
element.parameters,
(element.positionLeft*workspaceWidth) + "px");
if (elementIndex < element.displayId.split('_')[0])
elementIndex = element.displayId.split('_')[0];
elementIndex++;
});
clickEvent = 1;
$.each(result.elementConnections,
function(i, connection) {
connectEndpoints([connection.sourceEndpoint, connection.targetEndpoint, connection.parameters]);
});
clickEvent = 0;
setServiceStatus("saved");
});
});
});

9.06 KB | W: | H:

9.06 KB | W: | H:

circle/setty/static/setty/ubuntu.jpg
circle/setty/static/setty/ubuntu.jpg
circle/setty/static/setty/ubuntu.jpg
circle/setty/static/setty/ubuntu.jpg
  • 2-up
  • Swipe
  • Onion skin

19.9 KB | W: | H:

19.9 KB | W: | H:

circle/setty/static/setty/wordpress.jpg
circle/setty/static/setty/wordpress.jpg
circle/setty/static/setty/wordpress.jpg
circle/setty/static/setty/wordpress.jpg
  • 2-up
  • Swipe
  • Onion skin
# Copyright 2014 Budapest University of Technology and Economics (BME IK) # Copyright 2014 Budapest University of Technology and Economics (BME IK)
# #
# This file is part of CIRCLE Cloud. # This file is part of CIRCLE Cloud.
# #
# CIRCLE is free software: you can redistribute it and/or modify it under # CIRCLE 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 # the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) # Software Foundation, either version 3 of the License, or (at your option)
# any later version. # any later version.
# #
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY # CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details. # details.
# #
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django_tables2 import Table from django_tables2 import Table
from django_tables2.columns import TemplateColumn from django_tables2.columns import TemplateColumn
from setty.models import Service from setty.models import Service
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
class ServiceListTable(Table): class ServiceListTable(Table):
name = TemplateColumn( name = TemplateColumn(
template_name="setty/tables/column-name.html", template_name="setty/tables/column-name.html",
attrs={'th': {'data-sort': "string"}} attrs={'th': {'data-sort': "string"}}
) )
owner = TemplateColumn( owner = TemplateColumn(
template_name="setty/tables/column-owner.html", template_name="setty/tables/column-owner.html",
verbose_name=_("Owner"), verbose_name=_("Owner"),
attrs={'th': {'data-sort': "string"}} attrs={'th': {'data-sort': "string"}}
) )
running = TemplateColumn( running = TemplateColumn(
template_name="setty/tables/column-running.html", template_name="setty/tables/column-running.html",
verbose_name=_("Running"), verbose_name=_("Running"),
attrs={'th': {'data-sort': "string"}}, attrs={'th': {'data-sort': "string"}},
) )
class Meta: class Meta:
model = Service model = Service
attrs = {'class': ('table table-bordered table-striped table-hover' attrs = {'class': ('table table-bordered table-striped table-hover'
' template-list-table')} ' template-list-table')}
fields = ('name', 'owner', 'running', ) fields = ('name', 'owner', 'running', )
prefix = "service-" prefix = "service-"
...@@ -24,7 +24,8 @@ from django.shortcuts import redirect ...@@ -24,7 +24,8 @@ from django.shortcuts import redirect
from braces.views import LoginRequiredMixin from braces.views import LoginRequiredMixin
from django.views.generic import TemplateView, DeleteView from django.views.generic import TemplateView, DeleteView
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from .models import Element, ElementTemplate, ElementConnection, Service from saltstackhelper import *
from controller import *
from dashboard.views.util import FilterMixin from dashboard.views.util import FilterMixin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import json import json
...@@ -39,6 +40,7 @@ logger = logging.getLogger(__name__) ...@@ -39,6 +40,7 @@ logger = logging.getLogger(__name__)
class DetailView(LoginRequiredMixin, TemplateView): class DetailView(LoginRequiredMixin, TemplateView):
template_name = "setty/index.html" template_name = "setty/index.html"
salthelper = SaltStackHelper()
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
logger.debug('DetailView.get_context_data() called. User: %s', logger.debug('DetailView.get_context_data() called. User: %s',
...@@ -54,88 +56,37 @@ class DetailView(LoginRequiredMixin, TemplateView): ...@@ -54,88 +56,37 @@ class DetailView(LoginRequiredMixin, TemplateView):
raise PermissionDenied raise PermissionDenied
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
logger.debug('DetailView.post() called. User: %s',
unicode(self.request.user))
service = Service.objects.get(id=kwargs['pk']) service = Service.objects.get(id=kwargs['pk'])
if self.request.user != service.user or not self.request.user.is_superuser:
if self.request.user == service.user or self.request.user.is_superuser:
if self.request.POST.get('event') == "saveService":
data = json.loads(self.request.POST.get('data'))
service = Service.objects.get(id=kwargs['pk'])
service.name = data['serviceName']
service.save()
Element.objects.filter(service=service).delete()
for element in data['elements']:
elementObject = Element(
service=service,
parameters=element['parameters'],
display_id=element['displayId'],
position_left=element['positionLeft'],
position_top=element['positionTop'],
anchor_number=element['anchorNumber']
)
elementObject.save()
for elementConnection in data['elementConnections']:
sourceId = elementConnection['sourceId']
targetId = elementConnection['targetId']
sourceEndpoint = elementConnection['sourceEndpoint']
targetEndpoint = elementConnection['targetEndpoint']
connectionParameters = elementConnection['parameters']
targetObject = Element.objects.get(
display_id=targetId,
service=service)
sourceObject = Element.objects.get(
display_id=sourceId,
service=service)
connectionObject = ElementConnection(
target=targetObject,
source=sourceObject,
target_endpoint=targetEndpoint,
source_endpoint=sourceEndpoint,
parameters=connectionParameters
)
connectionObject.save()
return JsonResponse({'serviceName': service.name})
elif self.request.POST.get('event') == "loadService":
service = Service.objects.get(id=kwargs['pk'])
elementList = Element.objects.filter(service=service)
elementConnectionList = ElementConnection.objects.filter(
Q(target__in=elementList) | Q(source__in=elementList))
elements = []
elementConnections = []
for item in elementList:
elements.append({
'parameters': item.parameters,
'displayId': item.display_id,
'positionLeft': item.position_left,
'positionTop': item.position_top,
'anchorNumber': item.anchor_number})
for item in elementConnectionList:
elementConnections.append({
'targetEndpoint': item.target_endpoint,
'sourceEndpoint': item.source_endpoint,
'parameters': item.parameters})
return JsonResponse(
{'elements': elements,
'elementConnections': elementConnections,
'serviceName': service.name})
else:
raise PermissionDenied
else:
raise PermissionDenied raise PermissionDenied
result = {}
eventName = self.request.POST.get('event')
serviceId = kwargs['pk']
if eventName == 'loadService':
result = SettyController.loadService(serviceId)
elif eventName == "deploy":
result = SettyController.deploy(serviceId)
data = json.loads(self.request.POST.get('data'))
if eventName == "saveService":
result = SettyController.saveService(serviceId, data['serviceName'], data[
'serviceNodes'], data['machines'], data['elementConnections'])
elif eventName == "getMachineAvailableList":
result = SettyController.getMachineAvailableList(
serviceId, data["usedHostnames"])
elif eventName == "addServiceNode":
result = SettyController.addServiceNode(
data["elementTemplateId"])
elif eventName == "addMachine":
result = SettyController.addMachine(data["hostname"])
elif eventName == "getInformation":
result = SettyController.getInformation(
data['elementTemplateId'], data['hostname'])
return JsonResponse(result)
class DeleteView(LoginRequiredMixin, DeleteView): class DeleteView(LoginRequiredMixin, DeleteView):
...@@ -180,11 +131,16 @@ class CreateView(LoginRequiredMixin, TemplateView): ...@@ -180,11 +131,16 @@ class CreateView(LoginRequiredMixin, TemplateView):
if not service_name: if not service_name:
service_name = "Noname" service_name = "Noname"
service = Service( try:
name=service_name, serviceNameAvailable = Service.objects.get(name=service_name)
status="stopped", raise PermissionDenied
user=self.request.user except Service.DoesNotExist:
) pass
service = Service(name=service_name,
status=1,
user=self.request.user)
service.save() service.save()
return redirect('setty.views.service-detail', pk=service.pk) return redirect('setty.views.service-detail', pk=service.pk)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment