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) { function getCookie(name) {
var cookieValue = null; var cookieValue = null;
if (document.cookie && document.cookie !== '') { if (document.cookie && document.cookie !== '') {
...@@ -82,80 +83,108 @@ jsPlumb.ready(function() { ...@@ -82,80 +83,108 @@ jsPlumb.ready(function() {
var nextStepConstraint = 0; var nextStepConstraint = 0;
/* Functions. */ /* Functions. */
setServiceStatus = function(status) { setServiceStatus = function(status) {
if (status == "unsaved") { if (status == "unsaved") {
$("#serviceStatus").text(gettext("Unsaved")); $("#serviceStatus").text("Unsaved");
} else { }
else {
$("#serviceStatus").empty(); $("#serviceStatus").empty();
} }
}; };
addInfo = function(title, info, object, type) { addInfo = function(title, info, type, object) {
mainDiv = $("<div>", { id = object.attr("id").split("_")[1];
class: "row", $.post("", {
html: $("<div>", { event: "getInformation",
class: "col-xs-12 text-center", data: JSON.stringify({
html: row = $("<h4>", { "elementTemplateId": object.attr("id").split("_")[1],
html: title "hostname": object.attr("hostname")})
}) }, function(result) {
}) alert(result);
}).add($("<div>", { });
class: "row",
style: "margin-top: 16px", /*
html: $("<div>", { $("#informationContainer").empty();
class: "col-xs-12 text-center",
html: row = $("<textarea>", { switch(type){
class: "form-control", case "connection":
style: "text-align: justify;", div =
rows: "18", '<div class="row">' +
id: "infoInput", '<div class="col-xs-12 text-center">' +
disabled: !type, '<h4>' + title + '</h4>' +
text: info '</div>' +
}) '</div>&nbsp;' +
}) '<div class="row">' +
})); '<div class="col-xs-12">' +
controlDiv = $("<div>", { '<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
class: "row", '</div>' +
style: "margin-top: 16px", '</div>&nbsp;' +
html: $("<div>", { '<div class="row">' +
class: "col-xs-3 text-center", '<div class="col-xs-12 text-center">' +
html: $("<button>", { '<button id="removeConnection" class="btn btn-info">Remove connection</button>' +
class: "btn btn-success btn-block", '</div>' +
id: "addEndpoint", '</div>';
html: gettext("Add endpoint") break;
}) case "element":
}).add($("<div>", { div =
class: "col-xs-3 text-center", '<div class="row">' +
html: $("<button>", { '<div class="col-xs-12 text-center">' +
class: "btn btn-danger btn-block", '<h4>' + title + '</h4>' +
id: "removeEndpoint", '</div>' +
html: gettext("Delete endpoint") '</div>&nbsp;' +
}) '<div class="row">' +
})).add($("<div>", { '<div class="col-xs-12">' +
class: "col-xs-6 text-center", '<textarea class="form-control" rows="24" id="infoInput" placeholder="Config data"></textarea>' +
html: $("<button>", { '</div>' +
class: "btn btn-info btn-block", '</div>&nbsp;' +
id: "removeElementFromWorkspace", '<div class="row text-center">' +
html: gettext("Remove from workspace") '<label>Endpoints</label>' +
}) '</div>' +
})) '<div class="row">' +
}); '<div class="col-xs-6 text-center">' +
addElementDiv = $("<div>", { '<button id="addEndpoint" class="btn btn-success"><i class="fa fa-plus"></i></button>' +
class: "row", '</div>' +
style: "margin-top: 16px", '<div class="col-xs-6 text-center">' +
html: $("<div>", { '<button id="removeEndpoint" class="btn btn-danger"><i class="fa fa-minus"></i></button>' +
class: "col-xs-12 text-center", '</div>' +
html: row = $("<button>", { '</div>&nbsp;' +
class: "btn btn-success", '<div class="row">' +
id: "addElementToWorkspace", '<div class="col-xs-12 text-center">' +
html: gettext("Add to workspace") '<button id="removeElementFromWorkspace" class="btn btn-info">Remove from workspace</button>' +
}) '</div>' +
}) '</div>';
}); break;
case "elementTemplate":
$("#informationContainer").html(type?mainDiv.add(controlDiv):mainDiv.add(addElementDiv)); div =
'<div class="row">' +
'<div class="col-xs-12 text-center">' +
'<h4>' + title + '</h4>' +
'</div>' +
'</div>&nbsp;' +
'<div class="row">' +
'<div class="col-xs-12">' +
'<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
'</div>' +
'</div>&nbsp;' +
'<div class="row">' +
'<div class="col-xs-12 text-center">' +
'<button id="addElementToWorkspace" class="btn btn-success">Add to workspace</button>' +
'</div>' +
'</div>';
break;
}*/
// Here comes the ajax getInformation post.
// elementtemplateid vagy hostname
div = 0;
$("#informationContainer").append(div);
$("#infoInput").val(info);
$("#changeInformationDialog").modal('show'); $("#changeInformationDialog").modal('show');
...@@ -265,8 +294,10 @@ jsPlumb.ready(function() { ...@@ -265,8 +294,10 @@ jsPlumb.ready(function() {
anchors = element.attr("anchors"); anchors = element.attr("anchors");
id = element.attr("id"); id = element.attr("id");
for (i = 0; i < anchors; i++) { for(i=0;i<anchors;i++)
if (isConnected(i + "_" + id)) { {
if(isConnected(i + "_" + id))
{
return true; return true;
} }
} }
...@@ -298,7 +329,7 @@ jsPlumb.ready(function() { ...@@ -298,7 +329,7 @@ jsPlumb.ready(function() {
addEndpoint = function(element) { addEndpoint = function(element) {
anchors = element.attr("anchors"); anchors = element.attr("anchors");
if (anchors == 8) return 1; if (anchors == 8) return;
anchors++; anchors++;
...@@ -314,14 +345,12 @@ jsPlumb.ready(function() { ...@@ -314,14 +345,12 @@ jsPlumb.ready(function() {
element.attr("anchors", anchors); element.attr("anchors", anchors);
jsPlumbInstance.repaintEverything(); jsPlumbInstance.repaintEverything();
return 0;
}; };
removeEndoint = function(element) { removeEndoint = function(element) {
anchors = element.attr("anchors"); anchors = element.attr("anchors");
if (anchors == 4) return 1; if (anchors == 4) return;
i = --anchors; i = --anchors;
...@@ -350,14 +379,13 @@ jsPlumb.ready(function() { ...@@ -350,14 +379,13 @@ jsPlumb.ready(function() {
element.attr("anchors", anchors); element.attr("anchors", anchors);
jsPlumbInstance.repaintEverything(); jsPlumbInstance.repaintEverything();
return 0;
}; };
connectEndpoints = function(data) { connectEndpoints = function(data) {
connectionObject = connectionObject =
jsPlumbInstance.connect({ jsPlumbInstance.connect({
uuids: [data[0], data[1]] source: data[0],
target: data[1]
}); });
connectionObject.parameters = data[2]; connectionObject.parameters = data[2];
...@@ -381,7 +409,7 @@ jsPlumb.ready(function() { ...@@ -381,7 +409,7 @@ jsPlumb.ready(function() {
if (typeof idOrInstance != "string") { if (typeof idOrInstance != "string") {
newInstance = idOrInstance; newInstance = idOrInstance;
endpoints = newInstance.attr("anchors"); endpoints = newInstance.attr("anchomNumber");
newInstance.attr("anchors", 0); newInstance.attr("anchors", 0);
} else { } else {
newInstance = $('#' + idOrInstance) newInstance = $('#' + idOrInstance)
...@@ -412,14 +440,42 @@ jsPlumb.ready(function() { ...@@ -412,14 +440,42 @@ jsPlumb.ready(function() {
return newInstance; return newInstance;
}; };
addMachine = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) {
newInstance = "";
newInstance = $('<div>')
.prop("id", newId)
.prop("title", "Right click to delete")
.removeClass()
.addClass("element")
.attr("anchors", 0)
.attr("parameters", parameters)
.css("top", newPositionY)
.css("left", newPositionX);
$("#dropContainer").append(newInstance);
for (i = 0; i <= endpoints; i++) {
addEndpoint(newInstance);
}
jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
containment: $("#dropContainer")
});
setServiceStatus("unsaved");
jsPlumbInstance.repaintEverything();
return newInstance;
}
removeElement = function(object) { removeElement = function(object) {
jsPlumbInstance.detachAllConnections(object); jsPlumbInstance.detachAllConnections(object);
jsPlumbInstance.remove(object.attr("id")); jsPlumbInstance.remove(object.attr("id"));
}; };
/* Registering events using JsPlumb. */ /* Registering events using JsPlumb. */
jsPlumbInstance.bind("connection", function(info) { jsPlumbInstance.bind("connection", function(info) {
updateConnections(info.connection); updateConnections(info.connection);
...@@ -468,12 +524,20 @@ jsPlumb.ready(function() { ...@@ -468,12 +524,20 @@ jsPlumb.ready(function() {
jsPlumbInstance.detach(info); jsPlumbInstance.detach(info);
}); });
jsPlumbInstance.bind("dblclick", function(info) {
info.setPaintStyle({strokeStyle:"red", lineWidth: 8});
addInfo($("#" + info.sourceId.split('_')[1]).attr("alt") + ' - ' + $("#" + info.targetId.split('_')[1]).attr("alt"),
info.parameters,
"connection",
info);
});
jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), { jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
containment: $("#dropContainer") containment: $("#dropContainer")
}); });
/* Registering events using JQuery. */ /* Registering events using JQuery. */
$('body').on('click', '.elementTemplate', function() { $('body').on('click', '.elementTemplate', function() {
addElement($(this).attr("id"), addElement($(this).attr("id"),
...@@ -493,7 +557,7 @@ jsPlumb.ready(function() { ...@@ -493,7 +557,7 @@ jsPlumb.ready(function() {
element.addClass("elementSelected"); element.addClass("elementSelected");
addInfo(element.attr("alt"), addInfo(element.attr("alt"),
element.attr("parameters"), element.attr("parameters"),
element, 1); "element", element);
$(document).scrollTop(0); $(document).scrollTop(0);
}); });
...@@ -510,16 +574,21 @@ jsPlumb.ready(function() { ...@@ -510,16 +574,21 @@ jsPlumb.ready(function() {
stackIndexer++; stackIndexer++;
}); });
$('body').on('keyup', '#infoInput', function() { $('body').on('click', '#closeInfoPanel', function() {
$('#informationPanel').hide();
$('#dragPanel').show();
});
$('body').on('keyUp', '#infoInput', function() {
setServiceStatus("unsaved"); setServiceStatus("unsaved");
newParams = $("#infoInput").val(); newParams = $("#infoInput").val();
sharedObject.attr("parameters", newParams); if (type == "connection") object.parameters = newParams;
if (type == "element") object.attr("parameters", newParams);
}); });
$('body').on('click', '#addEndpoint', function() { $('body').on('click', '#addEndpoint', function() {
setServiceStatus("unsaved"); addEndpoint(sharedObject);
if(addEndpoint(sharedObject)) return;
undoStack.splice(stackIndexer, 0, removeEndoint); undoStack.splice(stackIndexer, 0, removeEndoint);
redoStack.splice(stackIndexer, 0, addEndpoint); redoStack.splice(stackIndexer, 0, addEndpoint);
objectStack.splice(stackIndexer, 0, sharedObject); objectStack.splice(stackIndexer, 0, sharedObject);
...@@ -528,8 +597,7 @@ jsPlumb.ready(function() { ...@@ -528,8 +597,7 @@ jsPlumb.ready(function() {
}); });
$('body').on('click', '#removeEndpoint', function() { $('body').on('click', '#removeEndpoint', function() {
setServiceStatus("unsaved"); removeEndoint(sharedObject);
if(removeEndoint(sharedObject)) return;
undoStack.splice(stackIndexer, 0, addEndpoint); undoStack.splice(stackIndexer, 0, addEndpoint);
redoStack.splice(stackIndexer, 0, removeEndoint); redoStack.splice(stackIndexer, 0, removeEndoint);
objectStack.splice(stackIndexer, 0, sharedObject); objectStack.splice(stackIndexer, 0, sharedObject);
...@@ -546,8 +614,6 @@ jsPlumb.ready(function() { ...@@ -546,8 +614,6 @@ jsPlumb.ready(function() {
objectStack.splice(stackIndexer, 0, sharedObject); objectStack.splice(stackIndexer, 0, sharedObject);
stackSize++; stackSize++;
stackIndexer++; stackIndexer++;
$("#changeInformationDialog").modal('hide');
}); });
$('body').on('click', '#removeConnection', function() { $('body').on('click', '#removeConnection', function() {
...@@ -568,7 +634,7 @@ jsPlumb.ready(function() { ...@@ -568,7 +634,7 @@ jsPlumb.ready(function() {
}); });
$('body').on('click', '#clearService', function() { $('body').on('click', '#clearService', function() {
//Todo jsPlumbInstance.remove("element");
setServiceStatus("unsaved"); setServiceStatus("unsaved");
elementIndex = 0; elementIndex = 0;
...@@ -593,12 +659,16 @@ jsPlumb.ready(function() { ...@@ -593,12 +659,16 @@ jsPlumb.ready(function() {
}); });
$('body').on('click', '#addMachineDialog', function() { $('body').on('click', '#addMachineDialog', function() {
// Here comes the ajax post of getting machines // Here comes the ajax post of getMachineAvailableList
// posting usedhostnames
//
//
// after it, appending obtained content to addmachinedialogbody
}); });
$('body').on('click', '.elementTemplateInfo', function() { $('body').on('click', '.elementTemplateInfo', function() {
id = $(this).attr("element"); id = $(this).attr("element");
addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), $("#" + id), 0); addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), "elementTemplate", $("#" + id));
}); });
$('body').on('click', '#serviceName', function() { $('body').on('click', '#serviceName', function() {
...@@ -622,8 +692,9 @@ jsPlumb.ready(function() { ...@@ -622,8 +692,9 @@ jsPlumb.ready(function() {
scrollContainer(1); scrollContainer(1);
}); });
$('body').on('hide.bs.modal', '#changeInformationDialog', function() { $('body').on('hide.bs.modal', '#changeInformationDialog', function () {
$('.element').removeClass('elementSelected'); $('.element').removeClass('elementSelected');
jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8});
}); });
$('body').on('keyup', '#searchElementTemplate', function() { $('body').on('keyup', '#searchElementTemplate', function() {
...@@ -656,53 +727,52 @@ jsPlumb.ready(function() { ...@@ -656,53 +727,52 @@ jsPlumb.ready(function() {
var eventObject = window.event ? event : e; var eventObject = window.event ? event : e;
// Undo (CTRL + Z) // Undo (CTRL + Z)
if (eventObject.keyCode == 90 && eventObject.ctrlKey) { if (eventObject.keyCode == 90 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#undoMovement').click(); $('#undoMovement').click();
} }
// Redo (CTRL + Y) // Redo (CTRL + Y)
if (eventObject.keyCode == 89 && eventObject.ctrlKey) { if (eventObject.keyCode == 89 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#redoMovement').click(); $('#redoMovement').click();
} }
// Add element (CTRL + A) // Add element (CTRL + A)
if (eventObject.keyCode == 65 && eventObject.ctrlKey) { if (eventObject.keyCode == 65 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#showAddElementDialog').click(); $('#showAddElementDialog').click();
} }
// Clean (CTRL + C) // Clean (CTRL + C)
if (eventObject.keyCode == 67 && eventObject.ctrlKey) { if (eventObject.keyCode == 67 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#clearService').click(); $('#clearService').click();
} }
// Save (CTRL + S) // Save (CTRL + S)
if (eventObject.keyCode == 83 && eventObject.ctrlKey) { if (eventObject.keyCode == 83 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#saveService').click(); $('#saveService').click();
} }
// Delete (CTRL + D) // Delete (CTRL + D)
if (eventObject.keyCode == 68 && eventObject.ctrlKey) { if (eventObject.keyCode == 68 && eventObject.ctrlKey)
{
eventObject.preventDefault(); eventObject.preventDefault();
$('#deleteService').click(); $('#deleteService').click();
} }
// Close dialog (ESC)
if (eventObject.keyCode == 27) {
eventObject.preventDefault();
$("#changeInformationDialog").modal('hide');
$("#addElementDialog").modal('hide');
}
}); });
$(window).on('resize', function() { $(window).on('resize', function() {
$(".element").each(function() { $(".element").each(function() {
rate = ($(this).position().left) / workspaceWidth; rate = ($(this).position().left)/workspaceWidth;
left = rate * ($("#dropContainer").width()); left = rate*($("#dropContainer").width());
$(this).css("left", left); $(this).css("left", left);
}); });
workspaceWidth = $("#dropContainer").width(); workspaceWidth = $("#dropContainer").width();
...@@ -710,7 +780,7 @@ jsPlumb.ready(function() { ...@@ -710,7 +780,7 @@ jsPlumb.ready(function() {
}); });
/* Registering events concerning persistence. */ /* Registering events concerning persistence. */
$('body').on('click', '#saveService', function() { $('body').on('click', '#saveService', function() {
serviceName = $("#serviceName").text(); serviceName = $("#serviceName").text();
...@@ -723,18 +793,16 @@ jsPlumb.ready(function() { ...@@ -723,18 +793,16 @@ jsPlumb.ready(function() {
"sourceEndpoint": elementConnections[index].endpoints[0].getUuid(), "sourceEndpoint": elementConnections[index].endpoints[0].getUuid(),
"targetId": elementConnections[index].targetId, "targetId": elementConnections[index].targetId,
"targetEndpoint": elementConnections[index].endpoints[1].getUuid(), "targetEndpoint": elementConnections[index].endpoints[1].getUuid(),
"parameters": elementConnections[index].parameters "parameters": elementConnections[index].parameters});
});
}); });
$.each($(".element"), function() { $.each($(".element"), function() {
instanceSet.push({ instanceSet.push({
"displayId": $(this).prop("id"), "displayId": $(this).prop("id"),
"positionLeft": $(this).position().left / workspaceWidth, "positionLeft": $(this).position().left/workspaceWidth,
"positionTop": $(this).position().top / workspaceHeight, "positionTop": $(this).position().top/workspaceHeight,
"anchorNumber": $(this).attr("anchors"), "anchorNumber": $(this).attr("anchors"),
"parameters": $(this).attr("parameters") "parameters": $(this).attr("parameters")});
});
}); });
$.post("", { $.post("", {
...@@ -742,28 +810,42 @@ jsPlumb.ready(function() { ...@@ -742,28 +810,42 @@ jsPlumb.ready(function() {
data: JSON.stringify({ data: JSON.stringify({
"serviceName": serviceName, "serviceName": serviceName,
"elementConnections": connectionSet, "elementConnections": connectionSet,
"elements": instanceSet "elements": instanceSet,
}) "machines": []}) //TODO: Dani: add machines here
}, function(result) { }, function(result) {
addMessage(result.serviceName + gettext(" saved successfully."), "success"); addMessage(result.serviceName + gettext(" saved successfully."),"success");
setServiceStatus("saved"); setServiceStatus("saved");
}); });
}); });
$(document).ready(function() { $(document).ready(function() {
if (!$("#dropContainer").length) return; // Protection for not posting sites that differ from setty sites. if(!$("#dropContainer").length)
return;
$.post("", { $.post("", {
event: "loadService" event: "loadService"
}, function(result) { }, function(result) {
$("#serviceName").text(result.serviceName); $("#serviceName").text(result.serviceName);
$.each(result.elements, function(i, element) { $.each(result.serviceNodes, function(i, element) {
addElement(element.displayId.split('_')[1], addElement(element.displayId.split('_')[1],
element.displayId, element.displayId,
(element.positionTop * workspaceHeight) + "px", (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.anchorNumber,
element.parameters, element.parameters,
(element.positionLeft * workspaceWidth) + "px"); (element.positionLeft*workspaceWidth) + "px");
if (elementIndex < element.displayId.split('_')[0]) if (elementIndex < element.displayId.split('_')[0])
elementIndex = element.displayId.split('_')[0]; elementIndex = element.displayId.split('_')[0];
elementIndex++; elementIndex++;
......

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
...@@ -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:
raise PermissionDenied
if self.request.user == service.user or self.request.user.is_superuser: result = {}
if self.request.POST.get('event') == "saveService": eventName = self.request.POST.get('event')
data = json.loads(self.request.POST.get('data')) serviceId = kwargs['pk']
service = Service.objects.get(id=kwargs['pk']) if eventName == 'loadService':
service.name = data['serviceName'] result = SettyController.loadService(serviceId)
service.save()
Element.objects.filter(service=service).delete() elif eventName == "deploy":
result = SettyController.deploy(serviceId)
for element in data['elements']: data = json.loads(self.request.POST.get('data'))
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}) 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'])
elif self.request.POST.get('event') == "loadService": return JsonResponse(result)
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
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