blob: d4cdaff1bc07d0a5b2a616a7a360944ccb84a16f [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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 __future__ import with_statement
import logging
import threading
import os
import ConfigParser
from tashi.rpycservices.rpyctypes import Host, Network, User, TashiException, Errors, HostState, Instance
from tashi.clustermanager.data import DataInterface
class FromConfig(DataInterface):
def __init__(self, config):
DataInterface.__init__(self, config)
self.log = logging.getLogger(__name__)
self.hosts = {}
self.instances = {}
self.networks = {}
self.users = {}
# self.locks = {}
self.lockNames = {}
self.instanceLock = threading.Lock()
self.lockNames[self.instanceLock] = "instanceLock"
self.instanceIdLock = threading.Lock()
self.lockNames[self.instanceIdLock] = "instanceIdLock"
self.maxInstanceId = 1
self.hostLocks = {}
self.hostLock = threading.Lock()
self.idLock = threading.Lock()
if not self.config.has_section("FromConfig"):
return
for (name, value) in self.config.items("FromConfig"):
name = name.lower()
if (name.startswith("host")):
host = eval(value)
if (host.__class__ is not Host):
raise ValueError, "Entry %s is not a Host" % (name)
host._lock = threading.Lock()
self.lockNames[host._lock] = "h%d" % (host.id)
self.hosts[host.id] = host
if (name.startswith("network")):
network = eval(value)
if (network.__class__ is not Network):
raise ValueError, "Entry %s is not a Network" % (name)
self.networks[network.id] = network
if (name.startswith("user")):
user = eval(value)
if (user.__class__ is not User):
raise ValueError, "Entry %s is not a User" % (name)
self.users[user.id] = user
def acquireLock(self, l):
l.acquire()
# self.locks[l] = threading.currentThread()
def releaseLock(self, l):
# del self.locks[l]
l.release()
def getNewInstanceId(self):
self.acquireLock(self.instanceIdLock)
instanceId = self.maxInstanceId
self.maxInstanceId = self.maxInstanceId + 1
self.releaseLock(self.instanceIdLock)
return instanceId
def registerInstance(self, instance):
if type(instance) is not Instance:
self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
raise TypeError
self.acquireLock(self.instanceLock)
try:
if (instance.id is not None and instance.id not in self.instances):
self.acquireLock(self.instanceIdLock)
if (instance.id >= self.maxInstanceId):
self.maxInstanceId = instance.id + 1
self.releaseLock(self.instanceIdLock)
else:
instance.id = self.getNewInstanceId()
instance._lock = threading.Lock()
self.lockNames[instance._lock] = "i%d" % (instance.id)
self.acquireLock(instance._lock)
self.instances[instance.id] = instance
finally:
self.releaseLock(self.instanceLock)
return instance
def acquireInstance(self, instanceId):
self.acquireLock(self.instanceLock)
try:
instance = self.instances.get(instanceId, None)
if (instance is None):
raise TashiException(d={'errno':Errors.NoSuchInstanceId,'msg':"No such instanceId - %d" % (instanceId)})
self.acquireLock(instance._lock)
finally:
self.releaseLock(self.instanceLock)
return instance
def releaseInstance(self, instance):
if type(instance) is not Instance:
self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
raise TypeError
try:
if (instance.id not in self.instances): # MPR: should never be true, but good to check
raise TashiException(d={'errno':Errors.NoSuchInstanceId,'msg':"No such instanceId - %d" % (instance.id)})
finally:
self.releaseLock(instance._lock)
def removeInstance(self, instance):
if type(instance) is not Instance:
self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
raise TypeError
self.acquireLock(self.instanceLock)
try:
del self.instances[instance.id]
self.releaseLock(instance._lock)
finally:
self.releaseLock(self.instanceLock)
def acquireHost(self, hostId):
if type(hostId) is not int:
self.log.exception("Argument is not of type int, but of type %s" % (type(hostId)))
raise TypeError
self.hostLock.acquire()
host = self.hosts.get(hostId, None)
if (host is None):
raise TashiException(d={'errno':Errors.NoSuchHostId,'msg':"No such hostId - %s" % (hostId)})
# hostLocks dict added when registerHost was implemented, otherwise newly added hosts don't have _lock
self.hostLocks[hostId] = self.hostLocks.get(hostId, threading.Lock())
host._lock = self.hostLocks[host.id]
self.acquireLock(host._lock)
return host
def releaseHost(self, host):
if type(host) is not Host:
self.log.exception("Argument is not of type Host, but of type %s" % (type(host)))
raise TypeError
try:
if (host.id not in self.hosts): # MPR: should never be true, but good to check
raise TashiException(d={'errno':Errors.NoSuchHostId,'msg':"No such hostId - %s" % (host.id)})
finally:
self.save()
self.releaseLock(host._lock)
self.hostLock.release()
def getHosts(self):
return self.hosts
def getHost(self, id):
host = self.hosts.get(id, None)
if (not host):
raise TashiException(d={'errno':Errors.NoSuchHostId,'msg':"No such hostId - %s" % (id)})
return host
def getInstances(self):
return self.instances
def getInstance(self, id):
instance = self.instances.get(id, None)
if (not instance):
raise TashiException(d={'errno':Errors.NoSuchInstanceId,'msg':"No such instanceId - %d" % (id)})
return instance
def getNetworks(self):
return self.networks
def getNetwork(self, id):
return self.networks[id]
def getUsers(self):
return self.users
def getUser(self, id):
return self.users[id]
def registerHost(self, hostname, memory, cores, version):
self.hostLock.acquire()
for id in self.hosts.keys():
if self.hosts[id].name == hostname:
host = Host(d={'id':id,'name':hostname,'state':HostState.Normal,'memory':memory,'cores':cores,'version':version})
self.hosts[id] = host
self.save()
self.hostLock.release()
return id, True
id = self.getNewId("hosts")
self.hosts[id] = Host(d={'id':id,'name':hostname,'state':HostState.Normal,'memory':memory,'cores':cores,'version':version})
self.save()
self.hostLock.release()
return id, False
def unregisterHost(self, hostId):
self.hostLock.acquire()
del self.hosts[hostId]
self.save()
self.hostLock.release()
def getNewId(self, table):
""" Generates id for a new object. For example for hosts and users.
"""
self.idLock.acquire()
maxId = 0
l = []
if(table == "hosts"):
for id in self.hosts.keys():
l.append(id)
if id >= maxId:
maxId = id
l.sort() # sort to enable comparing with range output
# check if some id is released:
t = range(maxId + 1)
t.remove(0)
if l != t and l != []:
releasedIds = filter(lambda x : x not in l, t)
self.idLock.release()
return releasedIds[0]
else:
self.idLock.release()
return maxId + 1
def save(self):
# XXXstroucki: a relative path? Where does it go
# and in what order does it get loaded
fileName = "./etc/Tashi.cfg"
if not os.path.exists(fileName):
file = open(fileName, "w")
file.write("[FromConfig]")
file.close()
parser = ConfigParser.ConfigParser()
parser.read(fileName)
if not parser.has_section("FromConfig"):
parser.add_section("FromConfig")
hostsInFile = []
for (name, value) in parser.items("FromConfig"):
name = name.lower()
if (name.startswith("host")):
hostsInFile.append(name)
for h in hostsInFile:
parser.remove_option("FromConfig", h)
for hId in self.hosts.keys():
host = self.hosts[hId]
hostPresentation = "Host(d={'id':%s,'name':'%s','state':HostState.Normal,'memory':%s,'cores':%s,'version':'%s'})" % (hId, host.name, host.memory, host.cores, host.version)
parser.set("FromConfig", "host%s" % hId, hostPresentation)
with open(fileName, 'wb') as configfile:
parser.write(configfile)