Common objects and relative test units added

- the common classes are needed for a more objected oriented style
- fixed pep8

Change-Id: I1a5dbb510168002c4c537beece4961741aed1d93
This commit is contained in:
Lisa Zangrando 2016-09-30 12:46:08 +02:00 committed by Vincent Llorens
parent 88e73f1399
commit a37e4fb0ff
35 changed files with 4203 additions and 0 deletions

View File

@ -0,0 +1,204 @@
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
"""
from nova.objects.base import NovaObject
from nova.objects.base import NovaObjectDictCompat
class BlockDeviceMapping(NovaObject, NovaObjectDictCompat):
fields = {
}
def __init__(self, *args, **kwargs):
super(BlockDeviceMapping, self).__init__(*args, **kwargs)
"""
class BlockDeviceMapping(object):
def __init__(self, id):
self.id = id
self.created_at = None
self.updated_at = None
self.deleted_at = None
self.device_name = None
self.delete_on_termination = None
self.snapshot_id = None
self.volume_id = None
self.volume_size = None
self.no_device = None
self.connection_info = None
self.instance_uuid = None
self.deleted = None
self.source_type = None
self.destination_type = None
self.guest_format = None
self.device_type = None
self.disk_bus = None
self.boot_index = None
self.image_id = None
def getId(self):
return self.id
def getImageId(self):
return self.image_id
def setImageId(self, image_id):
self.image_id = image_id
def getInstanceId(self):
return self.instance_uuid
def setInstanceId(self, instance_uuid):
self.instance_uuid = instance_uuid
def getSnapshotId(self):
return self.snapshot_id
def setSnapshotId(self, snapshot_id):
self.snapshot_id = snapshot_id
def getVolumeId(self):
return self.volume_id
def setVolumeId(self, volume_id):
self.volume_id = volume_id
def getVolumeSize(self):
return self.volume_size
def setVolumeSize(self, volume_size):
self.volume_size = volume_size
def getBootIndex(self):
return self.boot_index
def setBootIndex(self, boot_index):
self.boot_index = boot_index
def getCreatedAt(self):
return self.created_at
def setCreatedAt(self, created_at):
self.created_at = created_at
def getUpdatedAt(self):
return self.updated_at
def setUpdatedAt(self, updated_at):
self.updated_at = updated_at
def getDeletedAt(self):
return self.deleted_at
def setDeletedAt(self, deleted_at):
self.deleted_at = deleted_at
def getDeviceName(self):
return self.device_name
def setDeviceName(self, device_name):
self.device_name = device_name
def getNoDevice(self):
return self.no_device
def setNoDevice(self, no_device):
self.no_device = no_device
def getConnectionInfo(self):
return self.connection_info
def setConnectionInfo(self, connection_info):
self.connection_info = connection_info
def getDestinationType(self):
return self.destination_type
def setDestinationType(self, destination_type):
self.destination_type = destination_type
def getDeviceType(self):
return self.device_type
def setDeviceType(self, device_type):
self.device_type = device_type
def getSourceType(self):
return self.source_type
def setSourceType(self, source_type):
self.source_type = source_type
def getDiskBus(self):
return self.disk_bus
def setDiskBus(self, disk_bus):
self.disk_bus = disk_bus
def getGuestFormat(self):
return self.guest_format
def setGuestFormat(self, guest_format):
self.guest_format = guest_format
def isDeleteOnTermination(self):
return self.delete_on_termination
def setDeleteOnTermination(self, delete_on_termination):
self.delete_on_termination = delete_on_termination
def isDeleted(self):
return self.deleted
def setDeleted(self, deleted):
self.deleted = deleted
def serialize(self):
data = {}
data["id"] = self.id
data["created_at"] = self.created_at
data["updated_at"] = self.updated_at
data["deleted_at"] = self.deleted_at
data["device_name"] = self.device_name
data["device_type"] = self.device_type
data["delete_on_termination"] = self.delete_on_termination
data["snapshot_id"] = self.snapshot_id
data["volume_id"] = self.volume_id
data["volume_size"] = self.volume_size
data["no_device"] = self.no_device
data["connection_info"] = self.connection_info
data["instance_uuid"] = self.instance_uuid
data["deleted"] = self.deleted
data["source_type"] = self.source_type
data["destination_type"] = self.destination_type
data["guest_format"] = self.guest_format
data["disk_bus"] = self.disk_bus
data["boot_index"] = self.boot_index
data["image_id"] = self.image_id
blockDeviceMap = {}
blockDeviceMap["nova_object.version"] = "1.15"
blockDeviceMap["nova_object.namespace"] = "nova"
blockDeviceMap["nova_object.changes"] = ["device_name"]
blockDeviceMap["nova_object.name"] = "BlockDeviceMapping"
blockDeviceMap["nova_object.data"] = data
return blockDeviceMap

View File

@ -0,0 +1,44 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Compute(SynergyObject):
def __init__(self):
super(Compute, self).__init__()
def getHost(self):
return self.get("host")
def setHost(self, host):
self.set("host", host)
def getNodeName(self):
return self.get("nodename")
def setNodeName(self, nodename):
self.set("nodename", nodename)
def getLimits(self):
return self.get("limits")
def setLimits(self, limits):
self.set("limits", limits)

View File

@ -0,0 +1,64 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Endpoint(SynergyObject):
def __init__(self):
super(Endpoint, self).__init__()
self.set("enabled", False)
def getInterface(self):
return self.get("interface")
def setInterface(self, interface):
self.set("interface", interface)
def getRegion(self):
return self.get("region")
def setRegion(self, region):
self.set("region", region)
def getRegionId(self):
return self.get("region_id")
def setRegionId(self, region_id):
self.set("region_id", region_id)
def getServiceId(self):
return self.get("service_id")
def setServiceId(self, service_id):
self.set("service_id", service_id)
def getURL(self):
return self.get("url")
def setURL(self, url):
self.set("url", url)
def isEnabled(self):
return self.get("enabled")
def setEnabled(self, enabled=True):
self.set("enabled", enabled)

View File

@ -0,0 +1,48 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Flavor(SynergyObject):
def __init__(self):
super(Flavor, self).__init__()
self.set("vcpus", 0)
self.set("memory", 0)
self.set("storage", 0)
def getVCPUs(self):
return self.get("vcpus")
def setVCPUs(self, vcpus):
self.set("vcpus", vcpus)
def getMemory(self):
return self.get("memory")
def setMemory(self, memory):
self.set("memory", memory)
def getStorage(self):
return self.get("storage")
def setStorage(self, storage):
self.set("storage", storage)

View File

@ -0,0 +1,95 @@
from service import Service
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Hypervisor(Service):
def __init__(self):
super(Hypervisor, self).__init__()
self.set("vcpus", 0)
self.set("vcpus_used", 0)
self.set("memory", 0)
self.set("memory_used", 0)
self.set("storage", 0)
self.set("storage_used", 0)
self.set("vms", 0)
self.set("workload", 0)
def getIP(self):
return self.get("ip")
def setIP(self, ip):
self.set("ip", ip)
def getState(self):
return self.get("state")
def setState(self, state):
self.set("state", state)
def getWorkload(self):
return self.get("workload")
def setWorkload(self, workload):
self.set("workload", workload)
def getVMs(self):
return self.get("vms")
def setVMs(self, vms):
self.set("vms", vms)
def getVCPUs(self, used=False):
if used:
return self.get("vcpus_used")
else:
return self.get("vcpus")
def setVCPUs(self, vcpus, used=False):
if used:
self.set("vcpus_used", vcpus)
else:
self.set("vcpus", vcpus)
def getMemory(self, used=False):
if used:
return self.get("memory_used")
else:
return self.get("memory")
def setMemory(self, memory, used=False):
if used:
self.set("memory_used", memory)
else:
self.set("memory", memory)
def getStorage(self, used=False):
if used:
return self.get("storage_used")
else:
return self.get("storage")
def setStorage(self, storage, used=False):
if used:
self.set("storage_used", storage)
else:
self.set("storage", storage)

View File

@ -0,0 +1,65 @@
import threading
from datetime import datetime
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Priority(SynergyObject):
def __init__(self):
super(Priority, self).__init__()
self.condition = threading.Condition()
self.set("value", 0)
self.set("last_update", datetime.utcnow())
self.set("fairshare", {"vcpus": float(0),
"memory": float(0),
"disk": float(0)})
def getValue(self):
return self.get("value")
def setValue(self, value):
self.set("value", value)
self.set("last_update", datetime.utcnow())
def getLastUpdate(self):
return self.get("last_update")
def getFairShare(self, resource):
fairshare = self.get("fairshare")
if resource not in fairshare:
raise Exception("wrong resource %r" % resource)
return fairshare[resource]
def setFairShare(self, resource, value=0):
fairshare = self.get("fairshare")
if resource not in fairshare:
raise Exception("wrong resource %r" % resource)
with self.condition:
fairshare[resource] = value
self.condition.notifyAll()

View File

@ -0,0 +1,92 @@
from quota import Quota
from share import Share
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Project(SynergyObject):
def __init__(self):
super(Project, self).__init__()
self.set("data", {})
self.set("users", {})
self.set("share", Share())
self.set("quota", Quota())
self.set("TTL", float(0))
self.set("enabled", False)
def getData(self):
return self.get("data")
def getQuota(self):
return self.get("quota")
def getShare(self):
return self.get("share")
def getTTL(self):
return self.get("TTL")
def setTTL(self, TTL):
self.set("TTL", TTL)
def addUser(self, user):
if self.get("users").get(user.getId(), None):
raise Exception("user %r already exists!" % (user.getId()))
self.get("users")[user.getId()] = user
def getUser(self, id=None, name=None):
if id:
return self.get("users").get(id, None)
elif name:
for user in self.get("users").values():
if name == user.getName():
return user
return None
def getUsers(self):
return self.get("users").values()
def isEnabled(self):
return self.get("enabled")
def setEnabled(self, enabled=True):
self.set("enabled", enabled)
def main():
project = Project()
project.setId("22222222")
project.setName("LISA")
print(project.getName())
ser = project.serialize()
print(ser)
project1 = SynergyObject.deserialize(ser)
print(project1.serialize())
print(project1.getName())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,397 @@
import heapq
import json
import threading
from datetime import datetime
from sqlalchemy.exc import SQLAlchemyError
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class QueueItem(object):
def __init__(self, id, user_id, prj_id, priority,
retry_count, creation_time, last_update, data=None):
self.id = id
self.user_id = user_id
self.prj_id = prj_id
self.priority = priority
self.retry_count = retry_count
self.creation_time = creation_time
self.last_update = last_update
self.data = data
def getId(self):
return self.id
def setId(self, id):
self.id = id
def getUserId(self):
return self.user_id
def setUserId(self, user_id):
self.user_id = user_id
def getProjectId(self):
return self.prj_id
def setProjectId(self, prj_id):
self.prj_id = prj_id
def getPriority(self):
return self.priority
def setPriority(self, priority):
self.priority = priority
def getRetryCount(self):
return self.retry_count
def setRetryCount(self, retry_count):
self.retry_count = retry_count
def incRetryCount(self):
self.retry_count += 1
def getCreationTime(self):
return self.creation_time
def setCreationTime(self, creation_time):
self.creation_time = creation_time
def getLastUpdate(self):
return self.last_update
def setLastUpdate(self, last_update):
self.last_update = last_update
def getData(self):
return self.data
def setData(self, data):
self.data = data
class PriorityQueue(object):
def __init__(self):
self._heap = []
self._count = 0
def __len__(self):
return len(self._heap)
def __iter__(self):
"""Get all elements ordered by asc. priority. """
return self
def put(self, priority, item):
heapq.heappush(self._heap, (-priority, self._count, item))
self._count += 1
def get(self):
return heapq.heappop(self._heap)[2]
def size(self):
return len(self._heap)
def items(self):
return [heapq.heappop(self._heap) for i in range(len(self._heap))]
def smallest(self, x):
return heapq.nsmallest(x, self._heap)
def largest(self, x):
return heapq.nlargest(x, self._heap)
class QueueDB(object):
def __init__(self, name, db_engine, fairshare_manager=None):
self.name = name
self.db_engine = db_engine
self.fairshare_manager = fairshare_manager
self.is_closed = False
self.priority_updater = None
self.condition = threading.Condition()
self.pqueue = PriorityQueue()
self.createTable()
self.buildFromDB()
def getName(self):
return self.name
def getSize(self):
connection = self.db_engine.connect()
try:
QUERY = "select count(*) from `%s`" % self.name
result = connection.execute(QUERY)
row = result.fetchone()
return row[0]
except SQLAlchemyError as ex:
raise Exception(ex.message)
finally:
connection.close()
def createTable(self):
TABLE = """CREATE TABLE IF NOT EXISTS `%s` (`id` BIGINT NOT NULL \
AUTO_INCREMENT PRIMARY KEY, `priority` INT DEFAULT 0, user_id CHAR(40) \
NOT NULL, prj_id CHAR(40) NOT NULL, `retry_count` INT DEFAULT 0, \
`creation_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `last_update` \
TIMESTAMP NULL, `data` TEXT NOT NULL ) ENGINE=InnoDB""" % self.name
connection = self.db_engine.connect()
try:
connection.execute(TABLE)
except SQLAlchemyError as ex:
raise Exception(ex.message)
except Exception as ex:
raise Exception(ex.message)
finally:
connection.close()
def close(self):
if not self.is_closed:
self.is_closed = True
with self.condition:
self.condition.notifyAll()
def isClosed(self):
return self.is_closed
def buildFromDB(self):
connection = self.db_engine.connect()
try:
QUERY = "select id, user_id, prj_id, priority, retry_count, " \
"creation_time, last_update from `%s`" % self.name
result = connection.execute(QUERY)
for row in result:
queue_item = QueueItem(row[0], row[1], row[2],
row[3], row[4], row[5], row[6])
self.pqueue.put(row[3], queue_item)
except SQLAlchemyError as ex:
raise Exception(ex.message)
finally:
connection.close()
with self.condition:
self.condition.notifyAll()
def insertItem(self, user_id, prj_id, priority, data):
with self.condition:
idRecord = -1
QUERY = "insert into `%s` (user_id, prj_id, priority, " \
"data) values" % self.name
QUERY += "(%s, %s, %s, %s)"
connection = self.db_engine.connect()
trans = connection.begin()
try:
result = connection.execute(QUERY,
[user_id, prj_id, priority,
json.dumps(data)])
idRecord = result.lastrowid
trans.commit()
except SQLAlchemyError as ex:
trans.rollback()
raise Exception(ex.message)
finally:
connection.close()
now = datetime.now()
queue_item = QueueItem(idRecord, user_id, prj_id,
priority, 0, now, now)
self.pqueue.put(priority, queue_item)
self.condition.notifyAll()
def reinsertItem(self, queue_item):
with self.condition:
self.pqueue.put(queue_item.getPriority(), queue_item)
self.condition.notifyAll()
def getItem(self, blocking=True):
item = None
queue_item = None
with self.condition:
while (queue_item is None and not self.is_closed):
if len(self.pqueue):
queue_item = self.pqueue.get()
elif blocking:
self.condition.wait()
elif queue_item is None:
break
if (not self.is_closed and queue_item is not None):
connection = self.db_engine.connect()
try:
QUERY = """select user_id, prj_id, priority, \
retry_count, creation_time, last_update, data from `%s`""" % self.name
QUERY += " where id=%s"
result = connection.execute(QUERY, [queue_item.getId()])
row = result.fetchone()
item = QueueItem(queue_item.getId(), row[0], row[1],
row[2], row[3], row[4], row[5],
json.loads(row[6]))
except SQLAlchemyError as ex:
raise Exception(ex.message)
finally:
connection.close()
self.condition.notifyAll()
return item
def deleteItem(self, queue_item):
if not queue_item:
return
with self.condition:
connection = self.db_engine.connect()
trans = connection.begin()
try:
QUERY = "delete from `%s`" % self.name
QUERY += " where id=%s"
connection.execute(QUERY, [queue_item.getId()])
trans.commit()
except SQLAlchemyError as ex:
trans.rollback()
raise Exception(ex.message)
finally:
connection.close()
self.condition.notifyAll()
def updateItem(self, queue_item):
if not queue_item:
return
with self.condition:
connection = self.db_engine.connect()
trans = connection.begin()
try:
queue_item.setLastUpdate(datetime.now())
QUERY = "update `%s`" % self.name
QUERY += " set priority=%s, retry_count=%s, " \
"last_update=%s where id=%s"
connection.execute(QUERY, [queue_item.getPriority(),
queue_item.getRetryCount(),
queue_item.getLastUpdate(),
queue_item.getId()])
trans.commit()
except SQLAlchemyError as ex:
trans.rollback()
raise Exception(ex.message)
finally:
connection.close()
self.pqueue.put(queue_item.getPriority(), queue_item)
self.condition.notifyAll()
def updatePriority(self):
if self.fairshare_manager is None:
return
with self.condition:
queue_items = []
connection = self.db_engine.connect()
while len(self.pqueue) > 0:
queue_item = self.pqueue.get()
priority = queue_item.getPriority()
try:
priority = self.fairshare_manager.execute(
"CALCULATE_PRIORITY",
user_id=queue_item.getUserId(),
prj_id=queue_item.getProjectId(),
timestamp=queue_item.getCreationTime(),
retry=queue_item.getRetryCount())
queue_item.setPriority(priority)
except Exception as ex:
continue
finally:
queue_items.append(queue_item)
trans = connection.begin()
try:
queue_item.setLastUpdate(datetime.now())
QUERY = "update `%s`" % self.name
QUERY += " set priority=%s, last_update=%s where id=%s"
connection.execute(QUERY, [queue_item.getPriority(),
queue_item.getLastUpdate(),
queue_item.getId()])
trans.commit()
except SQLAlchemyError as ex:
trans.rollback()
raise Exception(ex.message)
connection.close()
if len(queue_items) > 0:
for queue_item in queue_items:
self.pqueue.put(queue_item.getPriority(), queue_item)
del queue_items
self.condition.notifyAll()
def toDict(self):
queue = {}
queue["name"] = self.name
queue["size"] = self.getSize()
if self.is_closed:
queue["status"] = "OFF"
else:
queue["status"] = "ON"
return queue

View File

@ -0,0 +1,548 @@
import logging
import threading
from datetime import datetime
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
LOG = logging.getLogger("quota")
class Quota(SynergyObject):
def __init__(self):
super(Quota, self).__init__()
private = {}
private["servers"] = {"active": [], "building": [], "error": []}
private["resources"] = {
"memory": {"used": float(0), "size": float(0)},
"vcpus": {"used": float(0), "size": float(0)},
"instances": {"used": float(0), "size": float(0)}}
shared = {}
shared["servers"] = {"active": [], "building": [], "error": []}
shared["resources"] = {
"memory": {"used": float(0), "size": float(0)},
"vcpus": {"used": float(0), "size": float(0)},
"instances": {"used": float(0), "size": float(0)}}
self.set("shared", shared)
self.set("private", private)
self.condition = threading.Condition()
def getType(self):
return self.get("type")
def setType(self, type):
self.set("type", type)
def getServers(self, status, private=True):
if private:
servers = self.get("private")["servers"]
else:
servers = self.get("shared")["servers"]
if status not in servers:
raise Exception("wrong status %r" % status)
return servers[status]
def reset(self):
with self.condition:
for resource in self.get("private")["resources"].values():
resource["used"] = 0
self.condition.notifyAll()
def getSize(self, resource, private=True):
if private:
resources = self.get("private")["resources"]
else:
resources = self.get("shared")["resources"]
if resource not in resources:
raise Exception("wrong resource %r" % resource)
return resources[resource]["size"]
def setSize(self, resource, value=0, private=True):
if private:
resources = self.get("private")["resources"]
else:
resources = self.get("shared")["resources"]
if resource not in resources:
raise Exception("wrong resource %r" % resource)
with self.condition:
resources[resource]["size"] = value
self.condition.notifyAll()
def getUsage(self, resource, private=True):
if private:
resources = self.get("private")["resources"]
else:
resources = self.get("shared")["resources"]
if resource not in resources:
raise Exception("wrong resource %r" % resource)
return resources[resource]["used"]
def setUsage(self, resource, value=0, private=True):
if private:
resources = self.get("private")["resources"]
else:
resources = self.get("shared")["resources"]
if resource not in resources:
raise Exception("wrong resource %r" % resource)
with self.condition:
resources[resource]["used"] = value
self.condition.notifyAll()
def allocate(self, server, blocking=True):
server_id = server.getId()
state = server.getState()
flavor = server.getFlavor()
vcpus = flavor.getVCPUs()
memory = flavor.getMemory()
found = False
if server.isEphemeral():
if SharedQuota.allocate(server, blocking):
LOG.info(">> SharedQuota.allocate OK")
shared = self.get("shared")
servers = shared["servers"]
resources = shared["resources"]
with self.condition:
resources["vcpus"]["used"] += vcpus
resources["memory"]["used"] += memory
resources["instances"]["used"] += 1
servers["active"].append(server_id)
self.condition.notifyAll()
return True
else:
LOG.info(">> SharedQuota.allocate NO")
return False
private = self.get("private")
servers = private["servers"]
resources = private["resources"]
if vcpus > resources["vcpus"]["size"] or \
memory > resources["memory"]["size"]:
raise Exception("the required resources for server %r "
"exceed the quota size" % server_id)
with self.condition:
if server_id in servers["active"]:
raise Exception("resources for server %r already allocated"
% server_id)
elif server_id in servers["building"]:
raise Exception("resources for server %r waiting "
"to be allocated" % server_id)
elif state:
resources["vcpus"]["used"] += vcpus
resources["memory"]["used"] += memory
resources["instances"]["used"] += 1
servers[state].append(server_id)
found = True
elif not blocking:
servers["building"].append(server_id)
while (not found and server_id in servers["building"]):
vcpus_size = resources["vcpus"]["size"]
vcpus_used = resources["vcpus"]["used"]
memory_size = resources["memory"]["size"]
memory_used = resources["memory"]["used"]
LOG.debug("allocating server_id=%s vcpus=%s "
"memory=%s [vcpus in use %s of %s; "
"memory in use %s of %s]"
% (server_id,
vcpus,
memory,
vcpus_used,
vcpus_size,
memory_used,
memory_size))
if (vcpus_size - vcpus_used >= vcpus) and \
(memory_size - memory_used >= memory):
found = True
resources["vcpus"]["used"] += vcpus
resources["memory"]["used"] += memory
resources["instances"]["used"] += 1
servers["active"].append(server_id)
servers["building"].remove(server_id)
LOG.info("allocated server_id=%s vcpus=%s memory"
"=%s [vcpus in use %s of %s; "
"memory in use %s of %s]"
% (server_id,
vcpus,
memory,
resources["vcpus"]["used"],
resources["vcpus"]["size"],
resources["memory"]["used"],
resources["memory"]["size"]))
elif blocking:
LOG.info("allocate wait!!!")
self.condition.wait()
else:
break
self.condition.notifyAll()
if not found:
servers["building"].remove(server_id)
return found
def release(self, server):
server_id = server.getId()
flavor = server.getFlavor()
vcpus = flavor.getVCPUs()
memory = flavor.getMemory()
if SharedQuota.release(server):
shared = self.get("shared")
servers = shared["servers"]
resources = shared["resources"]
with self.condition:
if server_id in servers["building"]:
servers["building"].remove(server_id)
elif server_id in servers["active"]:
resources["vcpus"]["used"] -= vcpus
resources["memory"]["used"] -= memory
resources["instances"]["used"] -= 1
if server_id in servers["active"]:
servers["active"].remove(server_id)
else:
servers["error"].remove(server_id)
self.condition.notifyAll()
return True
private = self.get("private")
servers = private["servers"]
resources = private["resources"]
found = False
with self.condition:
LOG.debug("releasing server_id=%s vcpus=%s memory=%s "
"[vcpu in use %s of %s; memory in use %s of %s]"
% (server_id,
vcpus,
memory,
resources["vcpus"]["used"],
resources["vcpus"]["size"],
resources["memory"]["used"],
resources["memory"]["size"]))
if server_id in servers["building"]:
servers["building"].remove(server_id)
found = True
elif server_id in servers["active"]:
if resources["vcpus"]["used"] - vcpus < 0:
resources["vcpus"]["used"] = 0
else:
resources["vcpus"]["used"] -= vcpus
if resources["memory"]["used"] - memory < 0:
resources["memory"]["used"] = 0
else:
resources["memory"]["used"] -= memory
resources["instances"]["used"] -= 1
if server_id in servers["active"]:
servers["active"].remove(server_id)
else:
servers["error"].remove(server_id)
LOG.info("released server_id=%s vcpus=%s memory=%s "
"[vcpu in use %s of %s; memory in use %s of %s]"
% (server_id,
vcpus,
memory,
resources["vcpus"]["used"],
resources["vcpus"]["size"],
resources["memory"]["used"],
resources["memory"]["size"]))
found = True
else:
LOG.debug("release: instance %r not found!" % (server_id))
self.condition.notifyAll()
return found
class SharedQuota(SynergyObject):
resources = {}
resources["memory"] = {"used": float(0), "size": float(0)}
resources["vcpus"] = {"used": float(0), "size": float(0)}
resources["instances"] = {"used": float(0), "size": float(-1)}
servers = {"active": [], "building": [], "error": []}
condition = threading.Condition()
lastAllocationTime = datetime.now()
lastReleaseTime = datetime.now()
enabled = False
def __init__(self):
super(SharedQuota, self).__init__()
self.set("servers", SharedQuota.servers)
self.set("resources", SharedQuota.resources)
self.set("enabled", SharedQuota.enabled)
self.set("lastAllocationTime", SharedQuota.lastAllocationTime)
self.set("lastReleaseTime", SharedQuota.lastReleaseTime)
@classmethod
def isEnabled(cls):
return cls.enabled
@classmethod
def enable(cls):
with cls.condition:
cls.enabled = True
cls.condition.notifyAll()
@classmethod
def disable(cls):
with cls.condition:
cls.enabled = False
cls.condition.notifyAll()
@classmethod
def getSize(cls, resource):
if resource not in cls.resources:
raise Exception("wrong resource %r" % resource)
return cls.resources[resource]["size"]
@classmethod
def setSize(cls, resource, value):
if resource not in cls.resources:
raise Exception("wrong resource %r" % resource)
with cls.condition:
cls.resources[resource]["size"] = value
cls.condition.notifyAll()
@classmethod
def getUsage(cls, resource):
if resource not in cls.resources:
raise Exception("wrong resource %r" % resource)
return cls.resources[resource]["used"]
@classmethod
def setUsage(cls, resource, value=0):
if resource not in cls.resources:
raise Exception("wrong resource %r" % resource)
with cls.condition:
cls.resources[resource]["used"] = value
cls.condition.notifyAll()
@classmethod
def getLastAllocationTime(cls):
return cls.lastAllocationTime
@classmethod
def getLastReleaseTime(cls):
return cls.lastReleaseTime
@classmethod
def wait(cls):
with cls.condition:
cls.condition.wait()
@classmethod
def allocate(cls, server, blocking=True):
server_id = server.getId()
state = server.getState()
flavor = server.getFlavor()
vcpus = flavor.getVCPUs()
memory = flavor.getMemory()
found = False
if vcpus > cls.resources["vcpus"]["size"] or \
memory > cls.resources["memory"]["size"]:
raise Exception("the required resources for server %r "
"exceed the quota size" % server_id)
with cls.condition:
if server_id in cls.servers["active"]:
raise Exception("resources for server %r already allocated"
% server_id)
elif server_id in cls.servers["building"]:
raise Exception("resources for server %r already waiting "
"to be allocated" % server_id)
elif state:
cls.resources["vcpus"]["used"] += vcpus
cls.resources["memory"]["used"] += memory
cls.resources["instances"]["used"] += 1
cls.servers[state].append(server_id)
found = True
else:
cls.servers["building"].append(server_id)
while (cls.enabled and not found and
server_id in cls.servers["building"]):
vcpus_size = cls.resources["vcpus"]["size"]
vcpus_used = cls.resources["vcpus"]["used"]
memory_size = cls.resources["memory"]["size"]
memory_used = cls.resources["memory"]["used"]
LOG.debug("allocating server_id=%s vcpus=%s "
"memory=%s [vcpus in use %s of %s; "
"memory in use %s of %s]"
% (server_id,
vcpus,
memory,
vcpus_used,
vcpus_size,
memory_used,
memory_size))
if (vcpus_size - vcpus_used >= vcpus) and \
(memory_size - memory_used >= memory):
found = True
cls.resources["vcpus"]["used"] += vcpus
cls.resources["memory"]["used"] += memory
cls.resources["instances"]["used"] += 1
cls.servers["active"].append(server_id)
cls.servers["building"].remove(server_id)
LOG.info("allocated server_id=%s vcpus=%s memory"
"=%s [vcpus in use %s of %s; "
"memory in use %s of %s]"
% (server_id,
vcpus,
memory,
cls.resources["vcpus"]["used"],
cls.resources["vcpus"]["size"],
cls.resources["memory"]["used"],
cls.resources["memory"]["size"]))
cls.lastAllocationTime = datetime.now()
elif blocking:
LOG.info("allocate wait!!!")
cls.condition.wait()
else:
break
cls.condition.notifyAll()
if not found:
cls.servers["building"].remove(server_id)
return found
@classmethod
def release(cls, server):
server_id = server.getId()
flavor = server.getFlavor()
vcpus = flavor.getVCPUs()
memory = flavor.getMemory()
found = False
with cls.condition:
LOG.debug("releasing server_id=%s vcpus=%s memory=%s "
"[vcpu in use %s of %s; memory in use %s of %s]"
% (server_id,
vcpus,
memory,
cls.resources["vcpus"]["used"],
cls.resources["vcpus"]["size"],
cls.resources["memory"]["used"],
cls.resources["memory"]["size"]))
if server_id in cls.servers["building"]:
cls.servers["building"].remove(server_id)
found = True
elif server_id in cls.servers["active"] or \
server_id in cls.servers["error"]:
if cls.resources["vcpus"]["used"] - vcpus < 0:
cls.resources["vcpus"]["used"] = 0
else:
cls.resources["vcpus"]["used"] -= vcpus
if cls.resources["memory"]["used"] - memory < 0:
cls.resources["memory"]["used"] = 0
else:
cls.resources["memory"]["used"] -= memory
if server_id in cls.servers["active"]:
cls.servers["active"].remove(server_id)
else:
cls.servers["error"].remove(server_id)
cls.resources["instances"]["used"] -= 1
LOG.info("released server_id=%s vcpus=%s memory=%s "
"[vcpu in use %s of %s; memory in use %s of %s]"
% (server_id,
vcpus,
memory,
cls.resources["vcpus"]["used"],
cls.resources["vcpus"]["size"],
cls.resources["memory"]["used"],
cls.resources["memory"]["size"]))
cls.lastReleaseTime = datetime.now()
found = True
else:
LOG.debug("release: instance %r not found!" % (server_id))
cls.condition.notifyAll()
return found
@classmethod
def deserialize(cls, entity):
quota = super(SharedQuota, cls).deserialize(entity)
cls.resources = entity["resources"]
cls.enabled = entity["enabled"]
cls.lastAllocationTime = datetime.strptime(
entity["lastAllocationTime"], "%Y-%m-%dT%H:%M:%S.%f")
cls.lastReleaseTime = datetime.strptime(
entity["lastReleaseTime"], "%Y-%m-%dT%H:%M:%S.%f")
return quota

View File

@ -0,0 +1,185 @@
import utils
from datetime import datetime
from flavor import Flavor
from server import Server
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Request(object):
def __init__(self):
self.context = None
self.instance = None
self.image = None
self.filter_properties = None
self.admin_password = None
self.injected_files = None
self.requested_networks = None
self.security_groups = None
self.block_device_mapping = None
self.legacy_bdm = None
def getAdminPassword(self):
return self.admin_password
def getId(self):
if self.instance:
return self.instance["nova_object.data"]["uuid"]
return None
def getInstance(self):
return self.instance
def getServer(self):
server = None
if self.instance:
instance_data = self.instance["nova_object.data"]
flavor_data = instance_data["flavor"]["nova_object.data"]
flavor = Flavor()
flavor.setId(flavor_data["flavorid"])
flavor.setName(flavor_data["name"])
flavor.setMemory(flavor_data["memory_mb"])
flavor.setVCPUs(flavor_data["vcpus"])
flavor.setStorage(flavor_data["root_gb"])
server = Server()
server.setFlavor(flavor)
server.setId(instance_data["uuid"])
server.setUserId(instance_data["user_id"])
server.setProjectId(instance_data["project_id"])
server.setCreatedAt(instance_data["created_at"])
server.setMetadata(instance_data["metadata"])
server.setKeyName(instance_data["key_name"])
if "user_data" in instance_data:
user_data = instance_data["user_data"]
if user_data:
server.setUserData(utils.decodeBase64(user_data))
return server
def getImage(self):
return self.image
def getUserId(self):
if self.instance:
return self.instance["nova_object.data"]["user_id"]
return None
def getProjectId(self):
if self.instance:
return self.instance["nova_object.data"]["project_id"]
return None
def getContext(self):
return self.context
def getCreatedAt(self):
if self.instance:
created_at = self.instance["nova_object.data"]["created_at"]
timestamp = datetime.strptime(created_at, "%Y-%m-%dT%H:%M:%SZ")
return timestamp
return 0
def getMetadata(self):
if self.instance:
return self.instance["nova_object.data"]["metadata"]
return None
def getRetry(self):
if self.filter_properties:
return self.filter_properties.get("retry", None)
return None
def getFilterProperties(self):
return self.filter_properties
def getInjectedFiles(self):
return self.injected_files
def getRequestedNetworks(self):
return self.requested_networks
def getSecurityGroups(self):
return self.security_groups
def getBlockDeviceMapping(self):
return self.block_device_mapping
def getLegacyBDM(self):
return self.legacy_bdm
def toDict(self):
request = {}
request['context'] = self.context
request['instance'] = self.instance
request['image'] = self.image
request['filter_properties'] = self.filter_properties
request['admin_password'] = self.admin_password
request['injected_files'] = self.injected_files
request['requested_networks'] = self.requested_networks
request['security_groups'] = self.security_groups
request['block_device_mapping'] = self.block_device_mapping
request['legacy_bdm'] = self.legacy_bdm
return request
@classmethod
def fromDict(cls, request_dict):
request = Request()
request.context = request_dict['context']
request.instance = request_dict['instance']
request.image = request_dict['image']
request.filter_properties = request_dict['filter_properties']
request.admin_password = request_dict['admin_password']
request.injected_files = request_dict['injected_files']
request.requested_networks = request_dict['requested_networks']
request.security_groups = request_dict['security_groups']
request.block_device_mapping = request_dict['block_device_mapping']
request.legacy_bdm = request_dict['legacy_bdm']
return request
@classmethod
def build(cls, context, instance, image, filter_properties,
admin_password, injected_files, requested_networks,
security_groups, block_device_mapping=None, legacy_bdm=True):
request = Request()
request.context = context
request.instance = instance
request.image = image
request.filter_properties = filter_properties
request.admin_password = admin_password
request.injected_files = injected_files
request.requested_networks = requested_networks
request.security_groups = security_groups
request.block_device_mapping = block_device_mapping
request.legacy_bdm = legacy_bdm
return request

View File

@ -0,0 +1,25 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Role(SynergyObject):
def __init__(self):
super(Role, self).__init__()

View File

@ -0,0 +1,136 @@
import synergy.common.utils as utils
from datetime import datetime
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Server(SynergyObject):
def __init__(self):
super(Server, self).__init__()
self.setType("permanent")
def __getDateTime(self, date):
if not date:
return None
elif isinstance(date, basestring):
return datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
elif isinstance(date, datetime):
return date
else:
raise Exception("not valid date format")
def getType(self):
return self.get("type")
def setType(self, type):
self.set("type", type)
def getState(self):
return self.get("state")
def setState(self, state):
self.set("state", state)
def getFlavor(self):
return self.get("flavor")
def setFlavor(self, flavor):
self.set("flavor", flavor)
def getKeyName(self):
return self.get("key_name")
def setKeyName(self, key_name):
self.set("key_name", key_name)
def getMetadata(self):
return self.get("metadata")
def setMetadata(self, metadata):
self.set("metadata", metadata)
if "quota" in metadata and metadata["quota"] == "shared":
self.setType("ephemeral")
else:
self.setType("permanent")
def getUserData(self):
return self.get("userdata")
def setUserData(self, userdata):
self.set("userdata", userdata)
if userdata:
try:
quota = utils.getConfigParameter(userdata, "quota", "synergy")
if quota is None or quota == "private":
self.setType("permanent")
elif quota == "shared":
self.setType("ephemeral")
else:
self.setType("permanent")
except Exception:
self.setType("permanent")
def getUserId(self):
return self.get("user_id")
def setUserId(self, user_id):
self.set("user_id", user_id)
def getProjectId(self):
return self.get("project_id")
def setProjectId(self, project_id):
self.set("project_id", project_id)
def getCreatedAt(self):
return self.get("created_at")
def setCreatedAt(self, created_at):
self.set("created_at", self.__getDateTime(created_at))
def getLaunchedAt(self):
return self.get("launched_at")
def setLaunchedAt(self, launched_at):
self.set("launched_at", self.__getDateTime(launched_at))
def getUpdatedAt(self):
return self.get("updated_at")
def setUpdatedAt(self, updated_at):
self.set("updated_at", self.__getDateTime(updated_at))
def getTerminatedAt(self):
return self.get("terminated_at")
def setTerminatedAt(self, terminated_at):
self.set("terminated_at", self.__getDateTime(terminated_at))
def isEphemeral(self):
return self.get("type") == "ephemeral"
def isPermanent(self):
return self.get("type") == "permanent"

View File

@ -0,0 +1,60 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Service(SynergyObject):
def __init__(self):
super(Service, self).__init__()
self.set("enabled", False)
self.set("endpoints", [])
def getType(self):
return self.get("type")
def setType(self, type):
self.set("type", type)
def getEndpoints(self):
return self.get("endpoints")
def getEndpoint(self, interface):
for endpoint in self.get("endpoints"):
if endpoint.getInterface() == interface:
return endpoint
return None
def getDescription(self):
return self.get("description")
def setDescription(self, description):
self.set("description", description)
def getStatus(self):
return self.get("status")
def setStatus(self, status):
self.set("status", status)
def isEnabled(self):
return self.get("status") == "enabled"

View File

@ -0,0 +1,48 @@
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Share(SynergyObject):
def __init__(self):
super(Share, self).__init__()
self.set("value", float(0))
self.set("sibling_value", float(0))
self.set("normalized_value", float(0))
def getValue(self):
return self.get("value")
def setValue(self, value):
self.set("value", value)
def getSiblingValue(self):
return self.get("sibling_value")
def setSiblingValue(self, value):
self.set("sibling_value", value)
def getNormalizedValue(self):
return self.get("normalized_value")
def setNormalizedValue(self, value):
self.set("normalized_value", value)

View File

@ -0,0 +1,184 @@
import json
import os.path
from datetime import datetime
from endpoint import Endpoint
from project import Project
from role import Role
from service import Service
from synergy.common.serializer import SynergyObject
from synergy_scheduler_manager.common.user import User
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Token(SynergyObject):
def __init__(self):
super(Token, self).__init__()
self.set("extras", {})
self.set("roles", [])
self.set("catalog", [])
@classmethod
def parse(cls, id, data):
token = Token()
token.setId(id)
data = data["token"]
token.setCreation(datetime.strptime(data["issued_at"],
"%Y-%m-%dT%H:%M:%S.%fZ"))
token.setExpiration(datetime.strptime(data["expires_at"],
"%Y-%m-%dT%H:%M:%S.%fZ"))
project = Project()
project.setId(data["project"]["id"])
project.setName(data["project"]["name"])
token.setProject(project)
user = User()
user.setId(data["user"]["id"])
user.setName(data["user"]["name"])
user.setProjectId(data["project"]["id"])
token.setUser(user)
token.getExtras().update(data["extras"])
for info in data["roles"]:
role = Role()
role.setId(info["id"])
role.setName(info["name"])
token.getRoles().append(role)
for service_info in data["catalog"]:
service = Service()
service.setId(service_info["id"])
service.setType(service_info["type"])
service.setName(service_info["name"])
for endpoint_info in service_info["endpoints"]:
endpoint = Endpoint()
endpoint.setId(endpoint_info["id"])
endpoint.setInterface(endpoint_info["interface"])
endpoint.setRegion(endpoint_info["region"])
endpoint.setRegionId(endpoint_info["region_id"])
endpoint.setURL(endpoint_info["url"])
service.getEndpoints().append(endpoint)
token.getServices().append(service)
return token
def getServices(self):
return self.get("catalog")
def getService(self, name):
for service in self.get("catalog"):
if service.getName() == name:
return service
return None
def getCreation(self):
return self.get("issued_at")
def setCreation(self, issued_at):
self.set("issued_at", issued_at)
def getExpiration(self):
return self.get("expires_at")
def setExpiration(self, expires_at):
self.set("expires_at", expires_at)
def getExtras(self):
return self.get("extras")
def getProject(self):
return self.get("project")
def setProject(self, project):
self.set("project", project)
def getRoles(self):
return self.get("roles")
def getUser(self):
return self.get("user")
def setUser(self, user):
self.set("user", user)
def isAdmin(self):
for role in self.get("roles"):
if role.getName() == "admin":
return True
return False
def issuedAt(self):
return self.get("issued_at")
def isExpired(self):
return self.getExpiration() < datetime.utcnow()
def save(self, filename):
# save to file
with open(filename, 'w') as f:
json.dump(self.serialize(), f)
@classmethod
def load(cls, filename):
if not os.path.isfile(filename):
return None
# load from file:
with open(filename, 'r') as f:
try:
data = json.load(f)
return Token.deserialize(data)
# if the file is empty the ValueError will be thrown
except ValueError as ex:
raise ex
def isotime(self, at=None, subsecond=False):
"""Stringify time in ISO 8601 format."""
if not at:
at = datetime.utcnow()
if not subsecond:
st = at.strftime('%Y-%m-%dT%H:%M:%S')
else:
st = at.strftime('%Y-%m-%dT%H:%M:%S.%f')
if at.tzinfo:
tz = at.tzinfo.tzname(None)
else:
tz = 'UTC'
st += ('Z' if tz == 'UTC' else tz)
return st

View File

@ -0,0 +1,156 @@
import json
import requests
from datetime import datetime
from token import Token
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class Trust(object):
def __init__(self, data):
self.id = data["id"]
self.impersonations = data["impersonation"]
self.trustor_user_id = data["trustor_user_id"]
self.trustee_user_id = data["trustee_user_id"]
self.links = data.get("links", [])
self.roles = data.get("roles", [])
self.remaining_uses = data["remaining_uses"]
self.expires_at = None
self.keystone_url = None
if data["expires_at"] is not None:
self.expires_at = datetime.strptime(data["expires_at"],
"%Y-%m-%dT%H:%M:%S.%fZ")
self.project_id = data["project_id"]
def getId(self):
return self.id
def isImpersonations(self):
return self.impersonations
def getRolesLinks(self):
return self.roles_links
def getTrustorUserId(self):
return self.trustor_user_id
def getTrusteeUserId(self):
return self.trustee_user_id
def getlinks(self):
return self.links
def getProjectId(self):
return self.project_id
def getRoles(self):
return self.roles
def getRemainingUses(self):
return self.remaining_uses
def getExpiration(self):
return self.expires_at
def isExpired(self):
if self.getExpiration() is None:
return False
return self.getExpiration() < datetime.utcnow()
def getToken(self, token_id):
headers = {"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "synergy"}
data = {}
data["auth"] = {"identity": {"methods": ["token"],
"token": {"id": token_id}},
"scope": {"OS-TRUST:trust": {"id": self.getId()}}}
response = requests.post(url=self.keystone_url + "/auth/tokens",
headers=headers,
data=json.dumps(data))
if response.status_code != requests.codes.ok:
response.raise_for_status()
if not response.text:
raise Exception("authentication failed!")
token_subject = response.headers["X-Subject-Token"]
token_data = response.json()
return Token.parse(token_subject, token_data)
@staticmethod
def makeTrust(trustee_user_id, token, expires_at=None, impersonation=True):
if token.isExpired():
raise Exception("token expired!")
headers = {"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "synergy",
"X-Auth-Token": token.getId()}
project_id = token.getProject().getId()
roles = token.getRoles()
roles_data = []
for role in roles:
roles_data.append({"id": role.getId(), "name": role.getName()})
data = {}
data["trust"] = {"impersonation": impersonation,
"project_id": project_id,
"roles": roles_data,
"trustee_user_id": trustee_user_id,
"trustor_user_id": token.getUser().getId()}
if expires_at is not None:
data["trust"]["expires_at"] = token.isotime(expires_at, True)
service = token.getService("keystone")
if not service:
raise Exception("keystone service not found!")
endpoint = service.getEndpoint("admin")
if not endpoint:
raise Exception("keystone endpoint not found!")
endpoint_url = endpoint.getURL()
response = requests.post(url=endpoint_url + "/OS-TRUST/trusts",
headers=headers,
data=json.dumps(data))
if response.status_code != requests.codes.ok:
response.raise_for_status()
if not response.text:
raise Exception("trust token failed!")
response = response.json()
trust = Trust(response["trust"])
trust.keystone_url = endpoint_url
return trust

View File

@ -0,0 +1,82 @@
from priority import Priority
from share import Share
from synergy.common.serializer import SynergyObject
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
class User(SynergyObject):
def __init__(self):
super(User, self).__init__()
self.set("data", {})
self.set("priority", Priority())
self.set("share", Share())
self.set("role", None)
self.set("enabled", False)
def getData(self):
return self.get("data")
def getProjectId(self):
return self.get("project_id")
def setProjectId(self, project_id):
self.set("project_id", project_id)
def getPriority(self):
return self.get("priority")
def getRole(self):
return self.get("role")
def setRole(self, role):
self.set("role", role)
def getShare(self):
return self.get("share")
def isEnabled(self):
return self.get("enabled")
def setEnabled(self, enabled=True):
self.set("enabled", enabled)
def main():
user = User()
user.setId("22222222")
user.setName("LISA")
user.setProjectId("pippo")
data = user.getData()
data["a"] = "b"
share = user.getShare()
share.setValue("10")
ser = user.serialize()
print(ser)
user1 = SynergyObject.deserialize(ser)
print(user1.serialize())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,48 @@
import base64
import binascii
import ConfigParser
import io
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
you may not use this file except in compliance with the
License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing
permissions and limitations under the License."""
def encodeBase64(s):
if not s:
return None
try:
return base64.encodestring(s)
except binascii.Error:
raise binascii.Error
def decodeBase64(s):
if not s:
return None
try:
return base64.decodestring(s)
except binascii.Error:
raise binascii.Error
def getConfigParameter(data, key, section="DEFAULT"):
config = ConfigParser.RawConfigParser(allow_no_value=True)
config.readfp(io.BytesIO(data))
return config.get(section, key)

View File

@ -0,0 +1,125 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.block_device import BlockDeviceMapping
from synergy_scheduler_manager.tests.unit import base
class TestBlockDeviceMapping(base.TestCase):
def setUp(self):
super(TestBlockDeviceMapping, self).setUp()
self.bdp = BlockDeviceMapping('id')
def test_set_get_Id(self):
self.assertEqual('id', self.bdp.getId())
def test_set_get_ImageId(self):
self.bdp.setImageId('im_id')
self.assertEqual('im_id', self.bdp.getImageId())
def test_set_get_InstaceId(self):
self.bdp.setInstanceId('inst_id')
self.assertEqual('inst_id', self.bdp.getInstanceId())
def test_set_get_SnapshotId(self):
self.bdp.setSnapshotId('snap_id')
self.assertEqual('snap_id', self.bdp.getSnapshotId())
def test_set_get_VolumeId(self):
self.bdp.setVolumeId('vol_id')
self.assertEqual('vol_id', self.bdp.getVolumeId())
def test_set_get_VolumeSize(self):
self.bdp.setVolumeSize('vol_size')
self.assertEqual('vol_size', self.bdp.getVolumeSize())
def test_set_get_BootIndex(self):
self.bdp.setBootIndex('boot_index')
self.assertEqual('boot_index', self.bdp.getBootIndex())
def test_set_get_CreatedAt(self):
self.bdp.setCreatedAt('now')
self.assertEqual('now', self.bdp.getCreatedAt())
def test_set_get_UpdatedAt(self):
self.bdp.setUpdatedAt('now')
self.assertEqual('now', self.bdp.getUpdatedAt())
def test_set_get_DeletedAt(self):
self.bdp.setDeletedAt('now')
self.assertEqual('now', self.bdp.getDeletedAt())
def test_set_get_DeviceName(self):
self.bdp.setDeviceName('name')
self.assertEqual('name', self.bdp.getDeviceName())
def test_set_get_NoDevice(self):
self.bdp.setNoDevice('no_dev')
self.assertEqual('no_dev', self.bdp.getNoDevice())
def test_set_get_ConnectionInfo(self):
self.bdp.setConnectionInfo('con_info')
self.assertEqual('con_info', self.bdp.getConnectionInfo())
def test_set_get_DestinationType(self):
self.bdp.setDestinationType('dest_type')
self.assertEqual('dest_type', self.bdp.getDestinationType())
def test_set_get_SourceType(self):
self.bdp.setSourceType('source_type')
self.assertEqual('source_type', self.bdp.getSourceType())
def test_set_get_DiskBus(self):
self.bdp.setDiskBus('disk_bus')
self.assertEqual('disk_bus', self.bdp.getDiskBus())
def test_set_get_GuestFormat(self):
self.bdp.setGuestFormat('guest_format')
self.assertEqual('guest_format', self.bdp.getGuestFormat())
def test_DeleteOnTermination(self):
self.bdp.setDeleteOnTermination('del_term')
self.assertEqual('del_term', self.bdp.isDeleteOnTermination())
def test_Deleted(self):
self.bdp.setDeleted('deleted')
self.assertEqual('deleted', self.bdp.isDeleted())
def test_serialize(self):
res = self.bdp.serialize()
expected = {'boot_index': None,
'connection_info': None,
'created_at': None,
'delete_on_termination': None,
'deleted': None,
'deleted_at': None,
'destination_type': None,
'device_name': None,
'device_type': None,
'disk_bus': None,
'guest_format': None,
'id': 'id',
'image_id': None,
'instance_uuid': None,
'no_device': None,
'snapshot_id': None,
'source_type': None,
'updated_at': None,
'volume_id': None,
'volume_size': None
}
self.assertEqual('1.15', res['nova_object.version'])
self.assertEqual('nova', res['nova_object.namespace'])
self.assertEqual(["device_name"], res["nova_object.changes"])
self.assertEqual("BlockDeviceMapping", res["nova_object.name"])
self.assertEqual(expected, res["nova_object.data"])

View File

@ -0,0 +1,32 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.compute import Compute
from synergy_scheduler_manager.tests.unit import base
class TestCompute(base.TestCase):
def setUp(self):
super(TestCompute, self).setUp()
self.comp = Compute()
def test_set_get_Host(self):
self.comp.setHost('host')
self.assertEqual('host', self.comp.getHost())
def test_set_get_NodeName(self):
self.comp.setNodeName('node_name')
self.assertEqual('node_name', self.comp.getNodeName())
def test_set_get_Limits(self):
self.comp.setLimits('limits')
self.assertEqual('limits', self.comp.getLimits())

View File

@ -0,0 +1,44 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.endpoint import Endpoint
from synergy_scheduler_manager.tests.unit import base
class TestEndpoint(base.TestCase):
def setUp(self):
super(TestEndpoint, self).setUp()
self.endp = Endpoint()
def test_set_get_interface(self):
self.endp.setInterface('pippo')
self.assertEqual('pippo', self.endp.getInterface())
def test_set__get_region(self):
self.endp.setRegion('region')
self.assertEqual('region', self.endp.getRegion())
def test_set_get_region_id(self):
self.endp.setRegionId('region_id')
self.assertEqual('region_id', self.endp.getRegionId())
def test_set_get_service_id(self):
self.endp.setServiceId('service_id')
self.assertEqual('service_id', self.endp.getServiceId())
def test_set_get_URL(self):
self.endp.setURL('URL')
self.assertEqual('URL', self.endp.getURL())
def test_set_isenable(self):
self.endp.setEnabled('true')
self.assertEqual('true', self.endp.isEnabled())

View File

@ -0,0 +1,32 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.flavor import Flavor
from synergy_scheduler_manager.tests.unit import base
class TestFlavor(base.TestCase):
def setUp(self):
super(TestFlavor, self).setUp()
self.flav = Flavor()
def test_set_get_VCPUs(self):
self.flav.setVCPUs(2)
self.assertEqual(2, self.flav.getVCPUs())
def test_set__get_Memory(self):
self.flav.setMemory('memory')
self.assertEqual('memory', self.flav.getMemory())
def test_set_get_Storage(self):
self.flav.setMemory('storage')
self.assertEqual('storage', self.flav.getMemory())

View File

@ -0,0 +1,54 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.hypervisor import Hypervisor
from synergy_scheduler_manager.tests.unit import base
class TestHypervisor(base.TestCase):
def setUp(self):
super(TestHypervisor, self).setUp()
self.hyp = Hypervisor()
def test_set_get_IP(self):
self.hyp.setIP('ip')
self.assertEqual('ip', self.hyp.getIP())
def test_set_get_State(self):
self.hyp.setState('state')
self.assertEqual('state', self.hyp.getState())
def test_set_get_Workload(self):
self.assertEqual(0, self.hyp.getWorkload())
self.hyp.setWorkload(8)
self.assertEqual(8, self.hyp.getWorkload())
def test_set_get_VMs(self):
self.assertEqual(0, self.hyp.getVMs())
self.hyp.setVMs(3)
self.assertEqual(3, self.hyp.getVMs())
def test_set_get_VCPUs(self):
self.assertEqual(0, self.hyp.getVCPUs(False))
self.assertEqual(0, self.hyp.getVCPUs(True))
self.hyp.setVCPUs(3, False)
self.hyp.setVCPUs(8, True)
self.assertEqual(3, self.hyp.getVCPUs(False))
self.assertEqual(8, self.hyp.getVCPUs(True))
def test_set_get_Memory(self):
self.assertEqual(0, self.hyp.getMemory(False))
self.assertEqual(0, self.hyp.getMemory(True))
self.hyp.setMemory(1, False)
self.hyp.setMemory(2, True)
self.assertEqual(1, self.hyp.getMemory(False))
self.assertEqual(2, self.hyp.getMemory(True))

View File

@ -0,0 +1,39 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
from synergy_scheduler_manager.common.priority import Priority
from synergy_scheduler_manager.tests.unit import base
class TestPriority(base.TestCase):
def setUp(self):
super(TestPriority, self).setUp()
self.priority = Priority()
def test_set_get_Value(self):
self.priority.setValue(1)
self.assertEqual(1, self.priority.getValue())
def test_set_get_LastUpdate(self):
self.assertNotEqual(datetime.utcnow(), self.priority.getLastUpdate())
def test_set_get_FairShare(self):
self.assertEqual(0.00, self.priority.getFairShare('vcpus'))
self.assertEqual(0.0, self.priority.getFairShare('memory'))
self.assertEqual(0.0, self.priority.getFairShare('disk'))
self.priority.setFairShare('vcpus', 2)
self.assertEqual(2, self.priority.getFairShare('vcpus'))
self.priority.setFairShare('memory', 5.6)
self.assertEqual(5.6, self.priority.getFairShare('memory'))
self.priority.setFairShare('disk', 0.1)
self.assertEqual(0.1, self.priority.getFairShare('disk'))

View File

@ -0,0 +1,71 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.project import Project
from synergy_scheduler_manager.common.user import User
from synergy_scheduler_manager.tests.unit import base
class TestProject(base.TestCase):
def setUp(self):
super(TestProject, self).setUp()
self.prj = Project()
def test_set_get_Data(self):
self.assertEqual({}, self.prj.getData())
def test_get_Quota(self):
sq = self.prj.getQuota()
sq.setSize('memory', 1024, True)
sq.setSize('vcpus', 100.00, True)
sq.setSize('instances', 10, True)
self.assertEqual(1024, sq.getSize('memory'))
self.assertEqual(100.0, sq.getSize('vcpus'))
self.assertEqual(10, sq.getSize('instances'))
def test_get_Share(self):
share = self.prj.getShare()
self.assertEqual(0.0, share.getValue())
self.assertEqual(0.00, share.getSiblingValue())
self.assertEqual(0.000, share.getNormalizedValue())
def test_set_get_TTL(self):
self.prj.setTTL(0.2)
self.assertEqual(0.2, self.prj.getTTL())
def test_set_is_Enable(self):
self.prj.setEnabled('True')
self.assertEqual('True', self.prj.isEnabled())
def test_get_add_User(self):
user1 = User()
user1.setId('id1')
user1.setName('name1')
self.prj.addUser(user1)
user2 = User()
user2.setId('id2')
user2.setName('name2')
self.prj.addUser(user2)
self.assertEqual('id1', self.prj.getUser('id1').getId())
self.assertEqual('name1', self.prj.getUser('id1').getName())
self.assertEqual('id2', self.prj.getUser('id2').getId())
self.assertEqual('name2', self.prj.getUser('id2').getName())
def test_get_Users(self):
user = User()
user.setId('id1')
user.setName('name')
self.prj.addUser(user)
self.assertEqual('name', self.prj.getUser('id1').getName())

View File

@ -0,0 +1,242 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import heapq
from mock import call
from mock import create_autospec
from sqlalchemy.engine.base import Engine
from synergy_scheduler_manager.common.queue import PriorityQueue
from synergy_scheduler_manager.common.queue import QueueDB
from synergy_scheduler_manager.common.queue import QueueItem
from synergy_scheduler_manager.tests.unit import base
class TestQueueItem(base.TestCase):
def setUp(self):
super(TestQueueItem, self).setUp()
self.qitem = QueueItem(id=1,
user_id=100,
prj_id=1,
priority=1000,
retry_count=1,
creation_time='now',
last_update='now',
data=1)
def test_get_set_id(self):
self.assertEqual(1, self.qitem.getId())
self.qitem.setId(8)
self.assertEqual(8, self.qitem.getId())
def test_get_set_userid(self):
self.assertEqual(100, self.qitem.getUserId())
self.qitem.setUserId(13)
self.assertEqual(13, self.qitem.getUserId())
def test_get_set_projectid(self):
self.assertEqual(1, self.qitem.getProjectId())
self.qitem.setProjectId(12)
self.assertEqual(12, self.qitem.getProjectId())
def test_get_set_priority(self):
self.assertEqual(1000, self.qitem.getPriority())
self.qitem.setPriority(10)
self.assertEqual(10, self.qitem.getPriority())
def test_retry_count(self):
self.assertEqual(1, self.qitem.getRetryCount())
self.qitem.setRetryCount(10)
self.assertEqual(10, self.qitem.getRetryCount())
self.qitem.incRetryCount()
self.assertEqual(11, self.qitem.getRetryCount())
def test_get_set_creation_time(self):
self.assertEqual("now", self.qitem.getCreationTime())
self.qitem.setCreationTime("later")
self.assertEqual("later", self.qitem.getCreationTime())
def test_get_set_last_update(self):
self.assertEqual("now", self.qitem.getLastUpdate())
self.qitem.setLastUpdate("later")
self.assertEqual("later", self.qitem.getLastUpdate())
def test_get_set_data(self):
self.assertEqual(1, self.qitem.getData())
self.qitem.setData(2)
self.assertEqual(2, self.qitem.getData())
class TestPriorityQueue(base.TestCase):
def setUp(self):
super(TestPriorityQueue, self).setUp()
self.pq = PriorityQueue()
def test_len(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual(3, self.pq.__len__())
def test_iter(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual('c', self.pq.__iter__().get())
self.assertEqual('b', self.pq.__iter__().get())
self.assertEqual('a', self.pq.__iter__().get())
def test_put_get(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual("c", self.pq.get())
self.assertEqual("b", self.pq.get())
self.assertEqual("a", self.pq.get())
def test_size(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual(3, self.pq.size())
def test_items(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual('c', self.pq.items()[0][2])
def test_smallest(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual('c', self.pq.smallest(1)[0][2])
def test_largest(self):
self.pq.put(1, "a")
self.pq.put(3, "b")
self.pq.put(10, "c")
self.assertEqual('a', self.pq.largest(1)[0][2])
class TestQueueDB(base.TestCase):
def setUp(self):
super(TestQueueDB, self).setUp()
# Create a Queue that mocks database interaction
self.db_engine_mock = create_autospec(Engine)
self.q = QueueDB(name="test", db_engine=self.db_engine_mock)
def test_get_name(self):
self.assertEqual('test', self.q.getName())
def test_close(self):
self.q.close()
self.assertEqual(True, self.q.isClosed())
def test_insert_item(self):
self.q.insertItem(user_id=1, prj_id=2, priority=10, data="mydata")
# Check the db call of the item insert
insert_call = call.connect().execute(
'insert into `test` (user_id, prj_id, priority, data) '
'values(%s, %s, %s, %s)', [1, 2, 10, '"mydata"'])
self.assertIn(insert_call, self.db_engine_mock.mock_calls)
# Check the item existence and values in the in-memory queue
priority, index, item = heapq.heappop(self.q.pqueue._heap)
self.assertEqual(-10, priority)
self.assertEqual(0, index)
self.assertEqual(1, item.user_id)
self.assertEqual(2, item.prj_id)
self.assertEqual(10, item.priority)
self.assertEqual(0, item.retry_count)
self.assertIsNone(item.data) # TODO(vincent): should it be "mydata"?
def test_get_size(self):
execute_mock = self.db_engine_mock.connect().execute
execute_call = call('select count(*) from `test`')
fetchone_mock = execute_mock().fetchone
fetchone_mock.return_value = [3]
# Check that getSize() uses the correct sqlalchemy method
self.assertEqual(3, self.q.getSize())
# Check that getSize() uses the correct SQL statement
self.assertEqual(execute_call, execute_mock.call_args)
def test_get_item(self):
# Insert the item and mock its DB insertion
execute_mock = self.db_engine_mock.connect().execute
execute_mock().lastrowid = 123
self.q.insertItem(user_id=1, prj_id=2, priority=10, data="mydata")
# Mock the DB select by returning the same things we inserted before
select_mock = self.db_engine_mock.connect().execute
select_call = call("select user_id, prj_id, priority, retry_count, "
"creation_time, last_update, data from `test` "
"where id=%s", [123])
fetchone_mock = select_mock().fetchone
fetchone_mock.return_value = [1, 2, 10, 0, "now", "now", '"mydata"']
item = self.q.getItem()
self.assertEqual(select_call, select_mock.call_args)
self.assertEqual(123, item.id)
self.assertEqual(1, item.user_id)
self.assertEqual(2, item.prj_id)
self.assertEqual(10, item.priority)
self.assertEqual(0, item.retry_count)
self.assertEqual("now", item.creation_time)
self.assertEqual("now", item.last_update)
self.assertEqual("mydata", item.data)
def test_delete_item(self):
# Mock QueueItem to be deleted
qitem = create_autospec(QueueItem)
qitem.getId.return_value = 123
# Mock the DB delete
execute_mock = self.db_engine_mock.connect().execute
execute_call = call("delete from `test` where id=%s", [123])
self.q.deleteItem(qitem)
self.assertEqual(execute_call, execute_mock.call_args)
def test_update_item(self):
# Mock QueueItem to be updated
qitem = create_autospec(QueueItem)
qitem.getPriority.return_value = 10
qitem.getRetryCount.return_value = 20
qitem.getLastUpdate.return_value = "right_now"
qitem.getId.return_value = 123
# Mock the DB update
execute_mock = self.db_engine_mock.connect().execute
execute_call = call("update `test` set priority=%s, retry_count=%s, "
"last_update=%s where id=%s",
[10, 20, "right_now", 123])
# Check the DB call and that the new QueueItem is in the queue
self.q.updateItem(qitem)
self.assertEqual(execute_call, execute_mock.call_args)
self.assertIn((-10, 0, qitem), self.q.pqueue._heap)

View File

@ -0,0 +1,200 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.flavor import Flavor
from synergy_scheduler_manager.common.quota import Quota
from synergy_scheduler_manager.common.quota import SharedQuota
from synergy_scheduler_manager.common.server import Server
from synergy_scheduler_manager.tests.unit import base
class TestQuota(base.TestCase):
def setUp(self):
super(TestQuota, self).setUp()
self.quota = Quota()
def test_get_set_Type(self):
self.quota.setType('Type')
self.assertEqual('Type', self.quota.getType())
def test_get_Servers(self):
self.assertEqual([], self.quota.getServers('active', private=True))
self.assertEqual([], self.quota.getServers('building', private=True))
self.assertEqual([], self.quota.getServers('error', private=True))
self.assertEqual([], self.quota.getServers('active', private=False))
self.assertEqual([], self.quota.getServers('building', private=False))
self.assertEqual([], self.quota.getServers('error', private=False))
def test_Reset(self):
self.quota.reset()
self.assertEqual(0.0, self.quota.get('private')[
'resources']['memory']['used'])
self.assertEqual(0.0, self.quota.get('private')[
'resources']['memory']['used'])
self.assertEqual(0.0, self.quota.get('private')[
'resources']['memory']['used'])
def test_set_get_Size(self):
self.quota.setSize('memory', 1024, private=True)
self.quota.setSize('vcpus', 100.00, private=True)
self.quota.setSize('instances', 10, private=True)
self.assertEqual(1024, self.quota.getSize('memory', private=True))
self.assertEqual(100.0, self.quota.getSize('vcpus', private=True))
self.assertEqual(10, self.quota.getSize('instances', private=True))
self.quota.setSize('memory', 1, private=False)
self.quota.setSize('vcpus', 11, private=False)
self.quota.setSize('instances', 111, private=False)
self.assertEqual(1, self.quota.getSize('memory', private=False))
self.assertEqual(11, self.quota.getSize('vcpus', private=False))
self.assertEqual(111, self.quota.getSize('instances', private=False))
def test_set_get_Usage(self):
self.quota.setUsage('memory', 1024, private=True)
self.quota.setUsage('vcpus', 100.00, private=True)
self.quota.setUsage('instances', 10, private=True)
self.assertEqual(1024, self.quota.getUsage('memory', private=True))
self.assertEqual(100.0, self.quota.getUsage('vcpus', private=True))
self.assertEqual(10, self.quota.getUsage('instances', private=True))
self.quota.setUsage('memory', 1024, private=False)
self.quota.setUsage('vcpus', 100.00, private=False)
self.quota.setUsage('instances', 10, private=False)
self.assertEqual(1024, self.quota.getUsage('memory', private=False))
self.assertEqual(100.0, self.quota.getUsage('vcpus', private=False))
self.assertEqual(10, self.quota.getUsage('instances', private=False))
self.quota.reset()
self.assertEqual(0, self.quota.getUsage('memory', private=True))
self.assertEqual(0, self.quota.getUsage('vcpus', private=True))
self.assertEqual(0, self.quota.getUsage('instances', private=True))
def test_Allocate(self):
self.quota.setSize("vcpus", 10, private=True)
self.quota.setSize("memory", 2048, private=True)
flavor = Flavor()
flavor.setVCPUs(3)
flavor.setMemory(1024)
server = Server()
server.setId("test_id")
server.setFlavor(flavor)
found = self.quota.allocate(server, blocking=False)
self.assertEqual(3, self.quota.getUsage('vcpus', private=True))
self.assertEqual(1024, self.quota.getUsage('memory', private=True))
self.assertEqual(True, found)
def test_release(self):
self.quota.setSize("vcpus", 10, private=True)
self.quota.setSize("memory", 2048, private=True)
flavor = Flavor()
flavor.setVCPUs(3)
flavor.setMemory(1024)
server = Server()
server.setId("test_id")
server.setFlavor(flavor)
self.quota.release(server)
self.assertEqual(0, self.quota.getUsage('vcpus', True))
self.assertEqual(0, self.quota.getUsage('memory', True))
class TestSharedQuota(base.TestCase):
def setUp(self):
super(TestSharedQuota, self).setUp()
self.quota = Quota()
def test_enabled_disable(self):
SharedQuota.enable()
self.assertEqual(True, SharedQuota.isEnabled())
SharedQuota.disable()
self.assertEqual(False, SharedQuota.isEnabled())
def test_set_get_Size(self):
SharedQuota.setSize("vcpus", 1024)
SharedQuota.setSize("memory", 2048)
SharedQuota.setSize("instances", 10)
self.assertEqual(1024, SharedQuota.getSize('vcpus'))
self.assertEqual(2048, SharedQuota.getSize('memory'))
self.assertEqual(10, SharedQuota.getSize('instances'))
def test_set_get_Usage(self):
SharedQuota.setUsage('memory', 1024)
SharedQuota.setUsage('vcpus', 30)
self.assertEqual(1024, SharedQuota.getUsage('memory'))
self.assertEqual(30, SharedQuota.getUsage('vcpus'))
def test_Allocate_Release(self):
SharedQuota.enable()
SharedQuota.setSize("vcpus", 20)
SharedQuota.setSize("memory", 4086)
self.quota.setSize("vcpus", 10)
self.quota.setSize("memory", 2048)
flavor1 = Flavor()
flavor1.setVCPUs(2)
flavor1.setMemory(2)
server1 = Server()
server1.setId("test_id1")
server1.setType("ephemeral")
server1.setFlavor(flavor1)
self.quota.allocate(server1, blocking=False)
self.assertEqual(2, SharedQuota.getUsage('memory'))
self.assertEqual(2, SharedQuota.getUsage('vcpus'))
self.assertEqual(0, self.quota.getUsage("memory", private=True))
self.assertEqual(0, self.quota.getUsage("vcpus", private=True))
flavor2 = Flavor()
flavor2.setVCPUs(3)
flavor2.setMemory(3)
server2 = Server()
server2.setId("test_id2")
server2.setType("permanent")
server2.setFlavor(flavor2)
self.quota.allocate(server2, blocking=False)
self.assertEqual(2, SharedQuota.getUsage('memory'))
self.assertEqual(2, SharedQuota.getUsage('vcpus'))
self.assertEqual(3, self.quota.getUsage("memory", private=True))
self.assertEqual(3, self.quota.getUsage("vcpus", private=True))
self.assertEqual(2, self.quota.getUsage("memory", private=False))
self.assertEqual(2, self.quota.getUsage("vcpus", private=False))
self.quota.release(server1)
self.assertEqual(0, SharedQuota.getUsage('memory'))
self.assertEqual(0, SharedQuota.getUsage('vcpus'))
self.assertEqual(0, self.quota.getUsage("vcpus", private=False))
self.assertEqual(0, self.quota.getUsage("vcpus", private=False))
self.quota.release(server2)
self.assertEqual(0, self.quota.getUsage("vcpus", private=True))
self.assertEqual(0, self.quota.getUsage("vcpus", private=True))

View File

@ -0,0 +1,431 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.request import Request
from synergy_scheduler_manager.tests.unit import base
class TestRequest(base.TestCase):
def setUp(self):
super(TestRequest, self).setUp()
req_dict = {
'legacy_bdm': True,
'requested_networks': None,
'injected_files': [],
'block_device_mapping': None,
'image': {
u'status': u'active',
u'created_at': u'2016-03-23T16:47:10.000000',
u'name': u'cirros',
u'deleted': False,
u'container_format': u'bare',
u'min_ram': 0,
u'disk_format': u'qcow2',
u'updated_at': u'2016-03-23T16:47:10.000000',
u'properties': {},
u'owner': u'1a6edd87f9ec41d8aa64c8f23d719c2a',
u'checksum': u'ee1eca47dc88f4879d8a229cc70a07c6',
u'min_disk': 0,
u'is_public': True,
u'deleted_at': None,
u'id': u'5100f480-a40c-46cd-b8b6-ea2e5e7bf09e',
u'size': 13287936},
'filter_properties': {
u'instance_type': {
u'nova_object.version': u'1.1',
u'nova_object.name': u'Flavor',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'memory_mb': 512,
u'root_gb': 1,
u'deleted_at': None,
u'name': u'm1.tiny',
u'deleted': False,
u'created_at': None,
u'ephemeral_gb': 0,
u'updated_at': None,
u'disabled': False,
u'vcpus': 1,
u'extra_specs': {},
u'swap': 0,
u'rxtx_factor': 1.0,
u'is_public': True,
u'flavorid': u'1',
u'vcpu_weight': 0,
u'id': 2}},
u'scheduler_hints': {}},
'instance': {
u'nova_object.version': u'2.0',
u'nova_object.name': u'Instance',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'vm_state': u'building',
u'pci_requests': {
u'nova_object.version': u'1.1',
u'nova_object.name': u'InstancePCIRequests',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'instance_uuid': u'e3a7770a-8875e2ccc68b',
u'requests': []}},
u'availability_zone': None,
u'terminated_at': None,
u'ephemeral_gb': 0,
u'instance_type_id': 2,
u'user_data': None,
u'numa_topology': None,
u'cleaned': False,
u'vm_mode': None,
u'flavor': {
u'nova_object.version': u'1.1',
u'nova_object.name': u'Flavor',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'memory_mb': 512,
u'root_gb': 1,
u'deleted_at': None,
u'name': u'm1.tiny',
u'deleted': False,
u'created_at': None,
u'ephemeral_gb': 0,
u'updated_at': None,
u'disabled': False,
u'vcpus': 1,
u'extra_specs': {},
u'swap': 0,
u'rxtx_factor': 1.0,
u'is_public': True,
u'flavorid': u'1',
u'vcpu_weight': 0,
u'id': 2}},
u'deleted_at': None,
u'reservation_id': u'r-s9v032d0',
u'id': 830,
u'security_groups': {
u'nova_object.version': u'1.0',
u'nova_object.name': u'SecurityGroupList',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'objects': []}},
u'disable_terminate': False,
u'root_device_name': None,
u'display_name': u'user_b1',
u'uuid': u'e3a7770a-dbf6-4b63-8f9a-8875e2ccc68b',
u'default_swap_device': None,
u'info_cache': {
u'nova_object.version': u'1.5',
u'nova_object.name': u'InstanceInfoCache',
u'nova_object.namespace': u'nova',
u'nova_object.data': {
u'instance_uuid': u'e3a7-8875e2ccc68b',
u'deleted': False,
u'created_at': u'2016-09-02T14:01:39Z',
u'updated_at': None,
u'network_info': u'[]',
u'deleted_at': None}},
u'hostname': u'user-b1',
u'launched_on': None,
u'display_description': u'user_b1',
u'key_data': None,
u'deleted': False,
u'power_state': 0,
u'key_name': None,
u'default_ephemeral_device': None,
u'progress': 0,
u'project_id': u'd20ac1ffa60841a78a865da63b2399de',
u'launched_at': None,
u'metadata': {
u'quota': u'dynamic',
u'persistent': u'False'},
u'node': None,
u'ramdisk_id': u'',
u'access_ip_v6': None,
u'access_ip_v4': None,
u'kernel_id': u'',
u'old_flavor': None,
u'updated_at': None,
u'host': None,
u'root_gb': 1,
u'user_id': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'system_metadata': {
u'image_min_disk': u'1',
u'image_min_ram': u'0',
u'image_disk_format': u'qcow2',
u'image_base_image_ref': u'5100f480-a25e7bf09e',
u'image_container_format': u'bare'},
u'task_state': u'scheduling',
u'shutdown_terminate': False,
u'cell_name': None,
u'ephemeral_key_uuid': None,
u'locked': False,
u'created_at': u'2016-09-02T14:01:39Z',
u'locked_by': None,
u'launch_index': 0,
u'memory_mb': 512,
u'vcpus': 1,
u'image_ref': u'a40c-46cd-b8b6-ea2e5e7bf09e',
u'architecture': None,
u'auto_disk_config': False,
u'os_type': None,
u'config_drive': u'',
u'new_flavor': None}},
'admin_password': u'URijD456Cezi',
'context': {
u'domain': None,
u'project_domain': None,
u'auth_token': u'f9d8458ef4ae454dad75f4636304079c',
u'resource_uuid': None,
u'read_only': False,
u'user_id': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'user_identity': u'fa60841a78a865da63b2399de - - -',
u'tenant': u'd20ac1ffa60841a78a865da63b2399de',
u'instance_lock_checked': False,
u'project_id': u'd20ac1ffa60841a78a865da63b2399de',
u'user_name': u'user_b1',
u'project_name': u'prj_b',
u'timestamp': u'2016-09-02T14:01:39.284558',
u'remote_address': u'10.64.31.19',
u'quota_class': None,
u'is_admin': False,
u'user': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'service_catalog': [],
u'read_deleted': u'no',
u'show_deleted': False,
u'roles': [u'user'],
u'request_id': u'req-69c9e7e6-62b2fee1d6e8',
u'user_domain': None},
'security_groups': [u'default']}
self.req = Request.fromDict(req_dict)
def test_get_AdminPassword(self):
self.assertEqual(u'URijD456Cezi', self.req.getAdminPassword())
def test_get_Id(self):
self.assertEqual(
u'e3a7770a-dbf6-4b63-8f9a-8875e2ccc68b',
self.req.getId())
def test_get_Instance(self):
ist = {
u'nova_object.data': {
u'access_ip_v4': None,
u'access_ip_v6': None,
u'architecture': None,
u'auto_disk_config': False,
u'availability_zone': None,
u'cell_name': None,
u'cleaned': False,
u'config_drive': u'',
u'created_at': u'2016-09-02T14:01:39Z',
u'default_ephemeral_device': None,
u'default_swap_device': None,
u'deleted': False,
u'deleted_at': None,
u'disable_terminate': False,
u'display_description': u'user_b1',
u'display_name': u'user_b1',
u'ephemeral_gb': 0,
u'ephemeral_key_uuid': None,
u'flavor': {
u'nova_object.data': {
u'created_at': None,
u'deleted': False,
u'deleted_at': None,
u'disabled': False,
u'ephemeral_gb': 0,
u'extra_specs': {},
u'flavorid': u'1',
u'id': 2,
u'is_public': True,
u'memory_mb': 512,
u'name': u'm1.tiny',
u'root_gb': 1,
u'rxtx_factor': 1.0,
u'swap': 0,
u'updated_at': None,
u'vcpu_weight': 0,
u'vcpus': 1},
u'nova_object.name': u'Flavor',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'1.1'},
u'host': None,
u'hostname': u'user-b1',
u'id': 830,
u'image_ref': u'a40c-46cd-b8b6-ea2e5e7bf09e',
u'info_cache': {
u'nova_object.data': {
u'created_at': u'2016-09-02T14:01:39Z',
u'deleted': False,
u'deleted_at': None,
u'instance_uuid': u'e3a7-8875e2ccc68b',
u'network_info': u'[]',
u'updated_at': None},
u'nova_object.name': u'InstanceInfoCache',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'1.5'},
u'instance_type_id': 2,
u'kernel_id': u'',
u'key_data': None,
u'key_name': None,
u'launch_index': 0,
u'launched_at': None,
u'launched_on': None,
u'locked': False,
u'locked_by': None,
u'memory_mb': 512,
u'metadata': {
u'persistent': u'False',
u'quota': u'dynamic'},
u'new_flavor': None,
u'node': None,
u'numa_topology': None,
u'old_flavor': None,
u'os_type': None,
u'pci_requests': {
u'nova_object.data': {
u'instance_uuid': u'e3a7770a-8875e2ccc68b',
u'requests': []},
u'nova_object.name': u'InstancePCIRequests',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'1.1'},
u'power_state': 0,
u'progress': 0,
u'project_id': u'd20ac1ffa60841a78a865da63b2399de',
u'ramdisk_id': u'',
u'reservation_id': u'r-s9v032d0',
u'root_device_name': None,
u'root_gb': 1,
u'security_groups': {
u'nova_object.data': {
u'objects': []},
u'nova_object.name': u'SecurityGroupList',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'1.0'},
u'shutdown_terminate': False,
u'system_metadata': {
u'image_base_image_ref': u'5100f480-a25e7bf09e',
u'image_container_format': u'bare',
u'image_disk_format': u'qcow2',
u'image_min_disk': u'1',
u'image_min_ram': u'0'},
u'task_state': u'scheduling',
u'terminated_at': None,
u'updated_at': None,
u'user_data': None,
u'user_id': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'uuid': u'e3a7770a-dbf6-4b63-8f9a-8875e2ccc68b',
u'vcpus': 1,
u'vm_mode': None,
u'vm_state': u'building'},
u'nova_object.name': u'Instance',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'2.0'}
self.assertEqual(ist, self.req.getInstance())
def test_get_Image(self):
im = {u'checksum': u'ee1eca47dc88f4879d8a229cc70a07c6',
u'container_format': u'bare',
u'created_at': u'2016-03-23T16:47:10.000000',
u'deleted': False,
u'deleted_at': None,
u'disk_format': u'qcow2',
u'id': u'5100f480-a40c-46cd-b8b6-ea2e5e7bf09e',
u'is_public': True,
u'min_disk': 0,
u'min_ram': 0,
u'name': u'cirros',
u'owner': u'1a6edd87f9ec41d8aa64c8f23d719c2a',
u'properties': {},
u'size': 13287936,
u'status': u'active',
u'updated_at': u'2016-03-23T16:47:10.000000'}
self.assertEqual(im, self.req.getImage())
def test_get_Context(self):
cont = {u'auth_token': u'f9d8458ef4ae454dad75f4636304079c',
u'domain': None,
u'instance_lock_checked': False,
u'is_admin': False,
u'project_domain': None,
u'project_id': u'd20ac1ffa60841a78a865da63b2399de',
u'project_name': u'prj_b',
u'quota_class': None,
u'read_deleted': u'no',
u'read_only': False,
u'remote_address': u'10.64.31.19',
u'request_id': u'req-69c9e7e6-62b2fee1d6e8',
u'resource_uuid': None,
u'roles': [u'user'],
u'service_catalog': [],
u'show_deleted': False,
u'tenant': u'd20ac1ffa60841a78a865da63b2399de',
u'timestamp': u'2016-09-02T14:01:39.284558',
u'user': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'user_domain': None,
u'user_id': u'4cb9f71a47914d0c8b78a471fd8f7015',
u'user_identity': u'fa60841a78a865da63b2399de - - -',
u'user_name': u'user_b1'}
self.assertEqual(cont, self.req.getContext())
def test_get_FilterProperties(self):
filt = {u'instance_type': {
u'nova_object.data': {u'created_at': None,
u'deleted': False,
u'deleted_at': None,
u'disabled': False,
u'ephemeral_gb': 0,
u'extra_specs': {},
u'flavorid': u'1',
u'id': 2,
u'is_public': True,
u'memory_mb': 512,
u'name': u'm1.tiny',
u'root_gb': 1,
u'rxtx_factor': 1.0,
u'swap': 0,
u'updated_at': None,
u'vcpu_weight': 0,
u'vcpus': 1},
u'nova_object.name': u'Flavor',
u'nova_object.namespace': u'nova',
u'nova_object.version': u'1.1'},
u'scheduler_hints': {}}
self.assertEqual(filt, self.req.getFilterProperties())
def test_get_InjectedFiles(self):
self.assertEqual([], self.req.getInjectedFiles())
def test_get_RequestedNetworks(self):
self.assertEqual(None, self.req.getRequestedNetworks())
def test_get_SecurityGroups(self):
self.assertEqual([u'default'], self.req.getSecurityGroups())
def test_get_BlockDeviceMapping(self):
self.assertEqual(None, self.req.getBlockDeviceMapping())
def test_get_LegacyBDM(self):
self.assertEqual(True, self.req.getLegacyBDM())
def test_get_Server(self):
prjId = self.req.getServer().getProjectId()
self.assertEqual('d20ac1ffa60841a78a865da63b2399de', prjId)
def test_from_to_Dict(self):
rq_dict = self.req.toDict()
self.assertEqual(True, rq_dict['legacy_bdm'])

View File

@ -0,0 +1,79 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
from synergy_scheduler_manager.common.server import Server
from synergy_scheduler_manager.tests.unit import base
class TestServer(base.TestCase):
def setUp(self):
super(TestServer, self).setUp()
self.server = Server()
def test_set_get_Type(self):
self.server.setType('type')
self.assertEqual('type', self.server.getType())
def test_set_get_State(self):
self.server.setState('state')
self.assertEqual('state', self.server.getState())
def test_set_get_Flavor(self):
self.server.setFlavor('flavor')
self.assertEqual('flavor', self.server.getFlavor())
def test_set_get_KeyName(self):
self.server.setKeyName('keyname')
self.assertEqual('keyname', self.server.getKeyName())
def test_set_get_Metadata(self):
self.server.setMetadata('metadata')
self.assertEqual('metadata', self.server.getMetadata())
def test_set_get_UserId(self):
self.server.setUserId('user_id')
self.assertEqual('user_id', self.server.getUserId())
def test_set_get_ProjectId(self):
self.server.setProjectId('project_id')
self.assertEqual('project_id', self.server.getProjectId())
def test_set_get_CreatedAt(self):
self.server.setCreatedAt('2015-02-10T13:00:10Z')
str_date = '2015-02-10T13:00:10Z'
datetime_date = datetime.strptime(str_date, "%Y-%m-%dT%H:%M:%SZ")
self.assertEqual(datetime_date, self.server.getCreatedAt())
def test_set_get_LaunchedAt(self):
self.server.setLaunchedAt('2015-02-10T13:00:10Z')
str_date = '2015-02-10T13:00:10Z'
datetime_date = datetime.strptime(str_date, "%Y-%m-%dT%H:%M:%SZ")
self.assertEqual(datetime_date, self.server.getLaunchedAt())
def test_set_get_UpdatedAt(self):
self.server.setUpdatedAt('2015-02-10T13:00:10Z')
str_date = '2015-02-10T13:00:10Z'
datetime_date = datetime.strptime(str_date, "%Y-%m-%dT%H:%M:%SZ")
self.assertEqual(datetime_date, self.server.getUpdatedAt())
def test_set_get_TerminatedAt(self):
self.server.setTerminatedAt('2015-02-10T13:00:10Z')
str_date = '2015-02-10T13:00:10Z'
datetime_date = datetime.strptime(str_date, "%Y-%m-%dT%H:%M:%SZ")
self.assertEqual(datetime_date, self.server.getTerminatedAt())
def test_is_Ephemeral(self):
self.assertEqual(False, self.server.isEphemeral())
def test_is_Permanent(self):
self.assertEqual(True, self.server.isPermanent())

View File

@ -0,0 +1,41 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.service import Service
from synergy_scheduler_manager.tests.unit import base
class TestService(base.TestCase):
def setUp(self):
super(TestService, self).setUp()
self.service = Service()
def test_set_get_Type(self):
self.service.setType('type')
self.assertEqual('type', self.service.getType())
def test_get_Endpoints(self):
self.assertEqual([], self.service.getEndpoints())
def test_get_Endpoint(self):
self.assertEqual(None, self.service.getEndpoint('interface'))
def test_set_get_Description(self):
self.service.setDescription('description')
self.assertEqual('description', self.service.getDescription())
def test_set_get_Status(self):
self.service.setStatus('enabled')
self.assertEqual('enabled', self.service.getStatus())
def test_isEnable(self):
self.assertEqual(False, self.service.isEnabled())

View File

@ -0,0 +1,32 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.user import Share
from synergy_scheduler_manager.tests.unit import base
class TestShare(base.TestCase):
def setUp(self):
super(TestShare, self).setUp()
self.share = Share()
def test_set_get_Value(self):
self.share.setValue('value')
self.assertEqual('value', self.share.getValue())
def test_set_get_SiblingValue(self):
self.share.setSiblingValue('sibling_value')
self.assertEqual('sibling_value', self.share.getSiblingValue())
def test_set_get_NormalizedValue(self):
self.share.setNormalizedValue('normalized_value')
self.assertEqual('normalized_value', self.share.getNormalizedValue())

View File

@ -0,0 +1,186 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
from synergy_scheduler_manager.common.project import Project
from synergy_scheduler_manager.common.token import Token
from synergy_scheduler_manager.common.user import User
from synergy_scheduler_manager.tests.unit import base
class TestToken(base.TestCase):
def setUp(self):
super(TestToken, self).setUp()
self.token = Token()
def test_get_Services(self):
self.assertEqual([], self.token.getServices())
def test_set_get_Creation(self):
self.token.setCreation('issue_at')
self.assertEqual('issue_at', self.token.getCreation())
def test_set_get_Expiration(self):
self.token.setExpiration('expires_at')
self.assertEqual('expires_at', self.token.getExpiration())
def test_set_get_Extras(self):
self.assertEqual({}, self.token.getExtras())
def test_set_get_Project(self):
prj = Project()
self.token.setProject(prj)
self.assertEqual(0.0, self.token.getProject().getTTL())
def test_get_Roles(self):
self.assertEqual({}, self.token.getExtras())
def test_set_get_User(self):
user = User()
self.token.setUser(user)
self.assertEqual({}, self.token.getUser().getData())
def test_isAdmin(self):
self.assertEqual(False, self.token.isAdmin())
def test_issuedAt(self):
self.token.setCreation('now')
self.assertEqual('now', self.token.issuedAt())
def test_isExpired(self):
str_date = '2015-02-10T13:00:10Z'
datetime_date = datetime.strptime(
str_date, "%Y-%m-%dT%H:%M:%SZ")
self.token.setExpiration(datetime_date)
self.assertEqual(True, self.token.isExpired())
def test_parse(self):
tok = {
u'token': {
u'methods': [u'password'],
u'roles': [{u'id': u'1efd5e18c8414086889ac93d8b11c411',
u'name': u'admin'}],
u'expires_at': u'2016-09-02T12:07:45.814651Z',
u'project': {u'domain': {u'id': u'default',
u'name': u'Default'},
u'id': u'1a6edd87f9ec41d8aa64c8f23d719c2a',
u'name': u'admin'},
u'catalog': [{
u'endpoints': [{
u'url': u'http://10.64.31.19:8774/v2/1a6edd8a',
u'interface': u'internal',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'ac178ac5b9f34647b9fce954966470c9'},
{u'url': u'http://10.64.31.19:8774/v2/1a6edd2a',
u'interface': u'admin',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'b81a3518d24d433495985a31740a5b84'},
{u'url': u'http://10.64.31.19:8774/v2/1a6ec2a',
u'interface': u'public',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'db03d5f72d89461582d4d87e7f82302a'}],
u'type': u'compute',
u'id': u'27dd094445aa42a9b05ca08c1f094d28',
u'name': u'nova'},
{
u'endpoints': [{
u'url': u'http://10.64.31.19:9292',
u'interface': u'internal',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'2f5458cf516147ffa1be04fabfbec9f8'},
{u'url': u'http://10.64.31.19:9292',
u'interface': u'admin',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'468db3a59f644d5d8cea849a'},
{u'url': u'http://10.64.31.19:9292',
u'interface': u'public',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'a13689dba17c432aa4c1f5b'}],
u'type': u'image',
u'id': u'6d80825e9f4544ea9a2d0a2d952b2e7c',
u'name': u'glance'},
{u'endpoints': [{u'url': u'http://10.64.31.19:9696',
u'interface': u'admin',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'567ed76f7161484f9c2556'},
{u'url': u'http://10.64.31.19:9696',
u'interface': u'internal',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'90373f0a87bc41cc99095'},
{u'url': u'http://10.64.31.19:9696',
u'interface': u'public',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'a95ad02ab '}],
u'type': u'network',
u'id': u'8f4c00132ccb422cbc0b6139266ad1df',
u'name': u'neutron'},
{u'endpoints': [{u'url': u'http://10.64.31.19:50v3',
u'interface': u'internal',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'494ccc932f0a6f8a86e629'},
{u'url': u'http://10.64.31.19:5/v3',
u'interface': u'public',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'5503912c691c2b25e1855f9'},
{u'url': u'http://10.64.31.19357/v3',
u'interface': u'admin',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'6d54bb99a2994ea8f527'}],
u'type': u'identity',
u'id': u'af19f5adf97c4f3fb1aa9d4fe499dd9',
u'name': u'keystone'},
{u'endpoints': [{u'url': u'http://10.64.31.19:8051',
u'interface': u'public',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'68d6e8128cf84037138a3d'},
{u'url': u'http://10.64.31.19:8051',
u'interface': u'admin',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'bc0bb63fd58044387a0e61b'},
{u'url': u'http://10.64.31.19:8051',
u'interface': u'internal',
u'region': u'RegionOne',
u'region_id': u'RegionOne',
u'id': u'f1bc92a85cc80bac0d'}],
u'type': u'management',
u'id': u'b1c0d32b48934ac380f6a231dce448f0',
u'name': u'synergy'}],
u'extras': {},
u'user': {u'domain': {u'id': u'default',
u'name': u'Default'},
u'id': u'9364456de70b46e59ba4dbd74498ccb0',
u'name': u'admin'},
u'audit_ids': [u'2XDA6g5nQeuuSg-vvhPzfw'],
u'issued_at': u'2016-09-02T11:57:45.814689Z'}}
self.tk = Token.parse('tok_id', tok)
self.assertEqual({}, self.tk.getExtras())
str_date = '2016-09-02T12:07:45.814651Z'
datetime_date = datetime.strptime(str_date,
"%Y-%m-%dT%H:%M:%S.%fZ")
self.assertEqual(datetime_date, self.tk.getExpiration())

View File

@ -0,0 +1,63 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from synergy_scheduler_manager.common.trust import Trust
from synergy_scheduler_manager.tests.unit import base
class TestTrust(base.TestCase):
def setUp(self):
super(TestTrust, self).setUp()
# fake data
data = {"id": "id", "trustor_user_id": "trustor_user_id",
"impersonation": "impersonation",
"trustee_user_id": "trustee_user_id",
"links": [],
"roles": [],
"remaining_uses": "remaining_uses",
"expires_at": None,
"keystone_url": None,
"project_id": "project_id"
}
self.trust = Trust(data)
def test_get_Id(self):
self.assertEqual('id', self.trust.getId())
def test_isImpersonations(self):
self.assertEqual('impersonation', self.trust.isImpersonations())
def getRolesLinks(self):
pass
def test_get_trustorUserId(self):
self.assertEqual('trustor_user_id', self.trust.getTrustorUserId())
def test_get_trusteeUserId(self):
self.assertEqual('trustee_user_id', self.trust.getTrusteeUserId())
def test_get_roles(self):
self.assertEqual([], self.trust.getRoles())
def test_get_links(self):
self.assertEqual([], self.trust.getlinks())
def test_get_remainingUses(self):
self.assertEqual("remaining_uses", self.trust.getRemainingUses())
def test_get_expiration(self):
self.assertEqual(None, self.trust.getExpiration())
def test_isExpired(self):
self.assertEqual(False, self.trust.isExpired())

View File

@ -0,0 +1,51 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
from synergy_scheduler_manager.common.user import User
from synergy_scheduler_manager.tests.unit import base
class TestUser(base.TestCase):
def setUp(self):
super(TestUser, self).setUp()
self.user = User()
def test_get_Data(self):
data = self.user.getData()
data['data'] = 'data'
self.assertEqual('data', data['data'])
def test_set_get_ProjectId(self):
self.user.setProjectId('project_id')
self.assertEqual('project_id', self.user.getProjectId())
def test_set_get_Role(self):
self.user.setRole('role')
self.assertEqual('role', self.user.getRole())
def test_get_Priority(self):
priority = self.user.getPriority()
self.assertEqual(0, priority.getValue())
self.assertNotEqual(datetime.utcnow(), priority.getLastUpdate())
self.assertEqual(0.0, priority.getFairShare('vcpus'))
self.assertEqual(0.0, priority.getFairShare('memory'))
self.assertEqual(0.0, priority.getFairShare('disk'))
def test_get_Share(self):
share = self.user.getShare()
self.assertEqual(0.0, share.getValue())
self.assertEqual(0.00, share.getSiblingValue())
self.assertEqual(0.000, share.getNormalizedValue())
def test_set_isenable(self):
self.user.setEnabled('true')
self.assertEqual('true', self.user.isEnabled())