blob: 7b531bf02c0065f56789de93947fe539e29c1c79 [file] [log] [blame]
import sqlalchemy as sa
from slavealloc.data import model
def denormalized_slaves(environments=None, purposes=None, pools=None, enabled=None):
locked_masters = model.masters.alias('locked_masters')
current_masters = model.masters.alias('current_masters')
q = sa.select([
model.slaves,
model.distros.c.name.label('distro'),
model.bitlengths.c.name.label('bitlength'),
model.speeds.c.name.label('speed'),
model.purposes.c.name.label('purpose'),
model.datacenters.c.name.label('datacenter'),
model.trustlevels.c.name.label('trustlevel'),
model.environments.c.name.label('environment'),
model.pools.c.name.label('pool'),
locked_masters.c.nickname.label('locked_master'),
current_masters.c.nickname.label('current_master'),
], whereclause=(
(model.distros.c.distroid == model.slaves.c.distroid) &
(model.bitlengths.c.bitsid == model.slaves.c.bitsid) &
(model.speeds.c.speedid == model.slaves.c.speedid) &
(model.purposes.c.purposeid == model.slaves.c.purposeid) &
(model.datacenters.c.dcid == model.slaves.c.dcid) &
(model.trustlevels.c.trustid == model.slaves.c.trustid) &
(model.environments.c.envid == model.slaves.c.envid) &
(model.pools.c.poolid == model.slaves.c.poolid) &
(model.slaves.c.envid != 5)
), from_obj=[
# note that the other tables will be joined automatically
model.slaves.outerjoin(
locked_masters, onclause=
locked_masters.c.masterid == model.slaves.c.locked_masterid
).outerjoin(
current_masters, onclause=
current_masters.c.masterid == model.slaves.c.current_masterid
)
])
if environments:
q = q.where(model.environments.c.name.in_(environments))
if purposes:
q = q.where(model.purposes.c.name.in_(purposes))
if pools:
q = q.where(model.pools.c.name.in_(pools))
if enabled:
q = q.where(model.slaves.c.enabled == enabled)
return q
denormalized_masters = sa.select([
model.masters,
model.datacenters.c.name.label('datacenter'),
model.pools.c.name.label('pool'),
], whereclause=(
(model.datacenters.c.dcid == model.masters.c.dcid) &
(model.pools.c.poolid == model.masters.c.poolid)
))
# this is one query, but it's easier to build it in pieces. Use bind parameter
# 'slaveid' to specify the new slave. There will be exactly one result row,
# unless there are no masters for this slave. That result row is from the
# masters table
def best_master():
# we need two copies of slaves: one to find this slave's info, and one
# enumerating its peers
me = model.slaves.alias('me')
peers = model.slaves.alias('peers')
# all of the peers of this slave, *not* including the slave itself
me_and_peers = me.join(peers, onclause=(
# include only slaves matching our pool
(me.c.poolid == peers.c.poolid) &
# .. and matching our silo
(me.c.distroid == peers.c.distroid) &
(me.c.bitsid == peers.c.bitsid) &
(me.c.purposeid == peers.c.purposeid) &
(me.c.dcid == peers.c.dcid) &
(me.c.trustid == peers.c.trustid) &
(me.c.envid == peers.c.envid) &
# .. but do not include the slave itself
(me.c.slaveid != peers.c.slaveid)
))
# find the peers' masters
peers_masters = me_and_peers.join(model.masters, onclause=(
(peers.c.current_masterid == model.masters.c.masterid)
))
# query all masterids with nonzero counts
nonzero_mastercounts = sa.select(
[model.masters.c.masterid, sa.func.count().label('slavecount')],
from_obj=peers_masters,
whereclause=(me.c.slaveid == sa.bindparam('slaveid')),
group_by=[model.masters.c.masterid],
).alias('nonzero_mastercounts')
# and join that as a subquery to get matching masters with no slaves
pool_masters = model.slaves.join(model.masters,
onclause=(model.slaves.c.poolid == model.masters.c.poolid))
joined_masters = pool_masters.outerjoin(nonzero_mastercounts,
onclause=(model.masters.c.masterid == nonzero_mastercounts.c.masterid))
# the slave counts in joined_masters are None where we'd like 0, so fix
# that
numeric_slavecount = sa.case(
[(nonzero_mastercounts.c.slavecount == None, 0)],
else_=nonzero_mastercounts.c.slavecount)
numeric_slavecount = numeric_slavecount.label('numeric_slavecount')
best_master = sa.select([model.masters],
from_obj=joined_masters,
whereclause=(
(model.slaves.c.slaveid == sa.bindparam('slaveid')) &
(model.masters.c.enabled)
),
order_by=[
numeric_slavecount, model.masters.c.masterid],
limit=1)
return best_master
best_master = best_master()
slave_password = sa.select([model.slave_passwords.c.password],
from_obj=[model.slaves, model.slave_passwords],
whereclause=(
(model.slaves.c.slaveid == sa.bindparam('slaveid')) &
(model.slave_passwords.c.poolid == model.slaves.c.poolid) &
((model.slave_passwords.c.distroid == None) |
(model.slave_passwords.c.distroid == model.slaves.c.distroid))))