create_release fix and provisioning added

This commit is contained in:
Nikolay Markov 2012-09-13 15:56:36 +04:00 committed by default
parent ba3fcea38b
commit a64d94c90f
22 changed files with 1062 additions and 100 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@
/build
nosetests.xml
nailgun.log
lock
.idea

View File

@ -41,101 +41,83 @@ def main():
logger.info("=== Creating release ===")
with open(params.release_file, "r") as f:
logger.debug("Trying to parse release file")
data = json.load(f)
logger.debug("Trying to parse release file")
data = json.load(f)
httpconn = httplib.HTTPConnection(host=params.host, port=params.port)
httpheaders = {"Content-Type": "application/json"}
httpdata = {}
for field in ('name', 'version', 'description', 'networks_metadata'):
httpdata[field] = data[field]
httpdata[field] = data[field]
logger.info("Request url: %s, data: %s" % \
('/api/releases', json.dumps(httpdata)))
if params.dry_run:
release_dict = {'id': '1'}
release_dict = {'id': '1'}
else:
logger.debug("Sending request")
try:
httpconn.request(method="POST",
url="/api/releases",
body=json.dumps(httpdata),
headers=httpheaders)
except Exception as e:
logger.error("Error: %s" % str(e))
sys.exit(1)
else:
response = httpconn.getresponse()
response_body = response.read()
logger.debug("Response status: %s" % response.status)
logger.debug("Response body: %s" % response_body)
release_dict = {}
logger.debug("Sending request")
try:
httpconn.request(method="POST",
url="/api/releases",
body=json.dumps(httpdata),
headers=httpheaders)
except Exception as e:
logger.error("Error: %s" % str(e))
sys.exit(1)
else:
response = httpconn.getresponse()
response_body = response.read()
logger.debug("Response status: %s" % response.status)
logger.debug("Response body: %s" % response_body)
if response.status == 200:
logger.info("Release '%s' has been successfully added" % \
httpdata['name'])
release_dict = json.loads(response_body)
logger.info("Release id: %s" % release_dict['id'])
elif response.status == 409:
logger.error("Release '%s' already exists" % httpdata['name'])
sys.exit(0)
elif response.status < 200 and response.status >= 300:
logger.error("Error in creating release: %s" % response.read())
sys.exit(1)
if response.status == 201:
logger.info("Release '%s' has been successfully added" % \
httpdata['name'])
release_dict = json.loads(response_body)
logger.info("Release id: %s" % release_dict['id'])
elif response.status == 409:
logger.error("Release '%s' already exists" % httpdata['name'])
sys.exit(0)
elif response.status < 201 and response.status >= 300:
logger.error("Error in creating release: %s" % response.read())
sys.exit(1)
def add_item(httpconn, handler_url, release,
item_collection, item_fields):
for item in item_collection:
httpdata = {}
for field in item_fields:
httpdata[field] = item[field]
for item in item_collection:
httpdata = {}
for field in item_fields:
httpdata[field] = item[field]
if params.dry_run:
httpdata['release'] = '1'
else:
httpdata['release'] = release
logger.debug("Request: url: %s, data: %s" % \
(handler_url, json.dumps(httpdata)))
if params.dry_run:
httpdata['release'] = '1'
else:
httpdata['release'] = release
logger.debug("Request: url: %s, data: %s" % \
(handler_url, json.dumps(httpdata)))
if not params.dry_run:
logger.debug("Sending request")
try:
httpconn.request(method="POST",
url=handler_url,
body=json.dumps(httpdata),
headers=httpheaders)
except Exception as e:
logger.error("Error: %s" % str(e))
raise e
else:
response = httpconn.getresponse()
response_body = response.read()
logger.debug("Response status: %s" % response.status)
logger.debug("Response body: %s" % response_body)
add_item(
httpconn, '/api/points', release_dict['id'],
data['points'],
('name', 'scheme')
)
add_item(
httpconn, '/api/coms', release_dict['id'],
data['components'],
('name', 'deploy', 'provides', 'requires')
)
add_item(
httpconn, '/api/roles', release_dict['id'],
data['roles'],
('name', 'components')
)
if not params.dry_run:
logger.debug("Sending request")
try:
httpconn.request(method="POST",
url=handler_url,
body=json.dumps(httpdata),
headers=httpheaders)
except Exception as e:
logger.error("Error: %s" % str(e))
raise e
else:
response = httpconn.getresponse()
response_body = response.read()
logger.debug("Response status: %s" % response.status)
logger.debug("Response body: %s" % response_body)
if __name__ == "__main__":

View File

@ -1,13 +1,21 @@
# -*- coding: utf-8 -*-
import json
import logging
import itertools
import web
import ipaddr
import netaddr
from models import Release, Cluster, Node, Role, Network, Vlan
from settings import settings
import rpc
from settings import settings
from provision import ProvisionConfig
from provision import ProvisionFactory
from provision.model.profile import Profile as ProvisionProfile
from provision.model.node import Node as ProvisionNode
from provision.model.power import Power as ProvisionPower
from models import Release, Cluster, Node, Role, Network, Vlan
def check_client_content_type(handler):
@ -229,6 +237,43 @@ class ClusterChangesHandler(JSONHandler):
if not cluster:
return web.notfound()
pc = ProvisionConfig()
pc.cn = "provision.driver.cobbler.Cobbler"
pc.url = settings.COBBLER_URL
pc.user = settings.COBBLER_USER
pc.password = settings.COBBLER_PASSWORD
try:
pd = ProvisionFactory.getInstance(pc)
except:
raise web.badrequest()
pf = ProvisionProfile(settings.COBBLER_PROFILE)
ndp = ProvisionPower("ssh")
ndp.power_user = "root"
for node in itertools.ifilter(
lambda n: n.status == "discover", cluster.nodes
):
nd = ProvisionNode(node.id)
nd.driver = pd
nd.mac = node.mac
nd.profile = pf
nd.pxe = True
nd.kopts = ""
nd.power = ndp
logging.debug(
"Trying to save node %s into provision system: profile: %s ",
node.id,
pf.name
)
nd.save()
logging.debug(
"Trying to reboot node %s using %s "
"in order to launch provisioning",
node.id,
ndp.power_type
)
nd.power_reboot()
message = {"method": "deploy", "args": {"var1": "Hello from nailgun"}}
rpc.cast('mcollective', message)

16
nailgun/logger.py Normal file
View File

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from settings import settings
from wsgilog import WsgiLog
class Log(WsgiLog):
def __init__(self, application):
WsgiLog.__init__(
self,
application,
logformat='%(message)s',
tofile=False,
toprint=True,
#file=settings.LOGFILE
)

View File

@ -9,11 +9,13 @@ import code
import web
from sqlalchemy.orm import scoped_session, sessionmaker
from api.handlers import check_client_content_type
from api.models import engine
from db import load_db_driver, syncdb
from unit_test import TestRunner
from urls import urls
from logger import Log
logging.basicConfig(level="DEBUG")
@ -97,7 +99,7 @@ if __name__ == "__main__":
logging.info("Running WSGI app...")
server = web.httpserver.WSGIServer(
("0.0.0.0", int(params.port)),
app.wsgifunc()
app.wsgifunc(Log)
)
try:
rpc_thread.start()

Binary file not shown.

View File

@ -0,0 +1,49 @@
import re
class ProvisionException(Exception):
pass
class ProvisionAlreadyExists(ProvisionException):
pass
class ProvisionDoesNotExist(ProvisionException):
pass
class ProvisionConfig:
cn = 'nailgun.provision.driver.cobbler.Cobbler'
class Provision:
def __init__(self):
raise NotImplementedError(
"Try to use ProvisionFactory.getInstance() method."
)
def save_profile(self):
raise NotImplementedError
def save_node(self):
raise NotImplementedError
class ProvisionFactory:
@classmethod
def getInstance(cls, config=ProvisionConfig()):
name = config.cn
module_name = '.'.join(re.split(ur'\.', name)[:-1])
class_name = re.split(ur'\.', name)[-1]
return getattr(
__import__(
module_name,
globals(),
locals(),
[class_name],
-1
),
class_name
)(config)

View File

@ -0,0 +1,366 @@
from provision import ProvisionException
from provision import ProvisionAlreadyExists, ProvisionDoesNotExist
from provision import Provision
import logging
import xmlrpclib
class Cobbler(Provision):
def __init__(self, config):
self.logger = logging.getLogger('provision.cobbler')
try:
self.url = config.url
self.user = config.user
self.password = config.password
except AttributeError as e:
self.logger.error(
'Provision configuration error.'
' Not all necessary attributes are set properly.'
)
raise e
self.logger.debug(
'Cobbler config: url="%s", user="%s", password="%s"',
self.url,
self.user,
self.password
)
try:
self.server = xmlrpclib.Server(self.url)
self.token = self.server.login(self.user, self.password)
except ProvisionException as e:
self.logger.error(
'Error occured while connecting to provision server.'
)
raise e
def _get_any_profile(self):
profiles = self.server.get_profiles(self.token)
if profiles:
return profiles[0]
raise ProvisionException("There is no available profiles")
def system_by_name(self, name):
systems = self.server.find_system({'name': name}, self.token)
if systems:
if len(systems) > 1:
self.logger.error(
"There are more than one system found by pattern: %s",
name
)
raise ProvisionException(
"There are more than one system found by pattern: %s",
name
)
return systems[0]
return None
# FIXME
# IT NEEDED TO BE IMPLEMENTED AS ONLY METHOD FOR ADD AND EDIT
def add_system(self, name, mac, power, profile, kopts=""):
if self.system_by_name(name):
self.logger.error(
"Trying to add system that already exists: %s",
name
)
raise ProvisionAlreadyExists(
"System with name %s already exists. Try to edit it.",
name
)
system_id = self.server.new_system(self.token)
self.server.modify_system(
system_id, 'name', name, self.token
)
self.server.modify_system(
system_id, 'profile', profile.name, self.token
)
self.server.modify_system(
system_id, 'kopts', kopts, self.token
)
self.server.modify_system(
system_id, 'modify_interface', {
"macaddress-eth0": mac,
}, self.token
)
self.server.modify_system(
system_id, 'power_type', power.power_type, self.token
)
if power.power_user:
self.server.modify_system(
system_id, 'power_user', power.power_user, self.token
)
if power.power_pass:
self.server.modify_system(
system_id, 'power_pass', power.power_pass, self.token
)
if power.power_id:
self.server.modify_system(
system_id, 'power_id', power.power_id, self.token
)
if power.power_address:
self.server.modify_system(
system_id, 'power_address', power.power_address, self.token
)
self.server.save_system(system_id, self.token)
return self.system_by_name(name)
def edit_system(self, name, mac, power, profile, kopts=""):
if not self.system_by_name(name):
self.logger.error(
"Trying to edit system that does not exist: %s",
name
)
raise ProvisionDoesNotExist(
"System with name %s does not exist. Try to edit it.",
name
)
system_id = self.server.get_system_handle(name, self.token)
self.server.modify_system(
system_id, 'profile', profile.name, self.token
)
self.server.modify_system(
system_id, 'kopts', kopts, self.token
)
self.server.modify_system(
system_id, 'modify_interface',
{
"macaddress-eth0": mac,
}, self.token
)
self.server.modify_system(
system_id, 'power_type', power.power_type, self.token
)
if power.power_user:
self.server.modify_system(
system_id, 'power_user', power.power_user, self.token
)
if power.power_pass:
self.server.modify_system(
system_id, 'power_pass', power.power_pass, self.token
)
if power.power_id:
self.server.modify_system(
system_id, 'power_id', power.power_id, self.token
)
if power.power_address:
self.server.modify_system(
system_id, 'power_address', power.power_address, self.token
)
self.server.save_system(system_id, self.token)
return self.system_by_name(name)
def power_system(self, name, power):
if not self.system_by_name(name):
self.logger.error(
"Trying to power system that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"System with name %s does not exist. Try to edit it." % name
)
if power not in ('on', 'off', 'reboot', 'status'):
raise ValueError("Power has invalid value")
system_id = self.server.get_system_handle(name, self.token)
self.server.power_system(system_id, power, self.token)
return self.system_by_name(name)
def handle_system(self, name, mac, power, profile, kopts=""):
try:
self.edit_system(name, mac, power, profile, kopts)
self.logger.info("Edited system: %s" % name)
except ProvisionDoesNotExist:
self.add_system(name, mac, power, profile, kopts)
self.logger.info("Added system: %s" % name)
def del_system(self, name):
system = self.system_by_name(name)
if not system:
self.logger.error(
"Trying to remove system that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"There is no system with name %s" % name
)
self.server.remove_system(name, self.token)
self.logger.info("Removed system %s" % name)
def profile_by_name(self, name):
profiles = self.server.find_profile({'name': name}, self.token)
if profiles:
if len(profiles) > 1:
self.logger.error(
"There are more than one profile found by pattern: %s",
name
)
raise ProvisionException(
"There are more than one profile found by pattern: %s",
name
)
return profiles[0]
return None
# FIXME
# IT NEEDED TO BE IMPLEMENTED AS ONLY METHOD FOR ADD AND EDIT
def add_profile(self, name, distro, kickstart):
if self.profile_by_name(name):
self.logger.error(
"Trying to add profile that already exists: %s" % name
)
raise ProvisionAlreadyExists(
"Profile with name %s already exists. Try to edit it.",
name
)
profile_id = self.server.new_profile(self.token)
self.server.modify_profile(profile_id, 'name', name, self.token)
self.server.modify_profile(profile_id, 'distro', distro, self.token)
self.server.modify_profile(
profile_id, 'kickstart', kickstart, self.token
)
self.server.save_profile(profile_id, self.token)
return self.profile_by_name(name)
def edit_profile(self, name, distro, kickstart):
if not self.profile_by_name(name):
self.logger.error(
"Trying to edit profile that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"Profile with name %s does not exist. Try to add it." % name
)
profile_id = self.server.get_profile_handle(name, self.token)
self.server.modify_profile(profile_id, 'distro', distro, self.token)
self.server.modify_profile(
profile_id, 'kickstart', kickstart, self.token
)
self.server.save_profile(profile_id, self.token)
return self.profile_by_name(name)
def handle_profile(self, name, distro, seed):
try:
self.edit_profile(name, distro, seed)
self.logger.info("Edited profile: %s" % name)
except ProvisionDoesNotExist:
self.add_profile(name, distro, seed)
self.logger.info("Added profile: %s" % name)
def del_profile(self, name):
profile = self.profile_by_name(name)
if not profile:
self.logger.error(
"Trying to remove profile that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"There is no profile with name %s" % name
)
self.server.remove_profile(name, self.token)
self.logger.info("Removed profile: %s" % name)
def distro_by_name(self, name):
distros = self.server.find_distro({'name': name}, self.token)
if distros:
if len(distros) > 1:
self.logger.error(
"There are more than one distro found by pattern: %s",
name
)
raise ProvisionException(
"There are more than one distro found by pattern %s",
name
)
return distros[0]
return None
# FIXME
# IT NEEDED TO BE IMPLEMENTED AS ONLY METHOD FOR ADD AND EDIT
def add_distro(self, name, kernel, initrd, arch, breed, osversion):
if self.distro_by_name(name):
self.logger.error(
"Trying to add distro that already exists: %s" % name
)
raise ProvisionAlreadyExists(
"Distro with name %s already exists. Try to edit it." % name
)
distro_id = self.server.new_distro(self.token)
self.server.modify_distro(distro_id, 'name', name, self.token)
self.server.modify_distro(distro_id, 'kernel', kernel, self.token)
self.server.modify_distro(distro_id, 'initrd', initrd, self.token)
self.server.modify_distro(distro_id, 'arch', arch, self.token)
self.server.modify_distro(distro_id, 'breed', breed, self.token)
self.server.modify_distro(
distro_id, 'os_version', osversion, self.token
)
self.server.save_distro(distro_id, self.token)
return self.distro_by_name(name)
def edit_distro(self, name, kernel, initrd, arch, breed, osversion):
if not self.distro_by_name(name):
self.logger.error(
"Trying to edit distro that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"Distro with name %s does not exist. Try to add it." % name
)
distro_id = self.server.get_distro_handle(name, self.token)
self.server.modify_distro(distro_id, 'kernel', kernel, self.token)
self.server.modify_distro(distro_id, 'initrd', initrd, self.token)
self.server.modify_distro(distro_id, 'arch', arch, self.token)
self.server.modify_distro(distro_id, 'breed', breed, self.token)
self.server.modify_distro(
distro_id, 'os_version', osversion, self.token
)
self.server.save_distro(distro_id, self.token)
return self.distro_by_name(name)
def handle_distro(self, name, kernel, initrd, arch, os, osversion):
try:
self.edit_distro(name, kernel, initrd, arch, os, osversion)
self.logger.info("Edited distro: %s" % name)
except ProvisionDoesNotExist:
self.add_distro(name, kernel, initrd, arch, os, osversion)
self.logger.info("Added distro: %s" % name)
def del_distro(self, name):
distro = self.distro_by_name(name)
if not distro:
self.logger.error(
"Trying to remove distro that does not exist: %s" % name
)
raise ProvisionDoesNotExist(
"There is no distro with name %s" % name
)
self.server.remove_distro(name, self.token)
self.logger.info("Removed distro %s" % name)
# API
def save_profile(self, profile):
self.handle_distro(profile.name,
profile.kernel,
profile.initrd,
profile.arch,
profile.os,
profile.osversion)
self.handle_profile(profile.name,
profile.name,
profile.seed)
def save_node(self, node):
self.handle_system(node.name,
node.mac,
node.power,
node.profile,
node.kopts,
)
def power_on(self, node):
self.power_system(node.name, 'on')
def power_off(self, node):
self.power_system(node.name, 'off')
def power_reboot(self, node):
self.power_system(node.name, 'reboot')
def power_status(self, node):
raise NotImplementedError

View File

View File

@ -0,0 +1,81 @@
import re
from provision import ProvisionException
import logging
class ModelObject(object):
_driver = None
@property
def driver(self):
if self._driver is None:
raise ProvisionException("Driver is not set properly.")
return self._driver
@driver.setter
def driver(self, driver):
self._driver = driver
class Validator:
_supported_os = (
"ubuntu",
"redhat",
)
_supported_osversion = (
"precise",
"rhel6",
)
_supported_arch = (
"x86_64",
)
_supported_platform = (
("ubuntu", "precise", "x86_64"),
("redhat", "rhel6", "x86_64"),
)
_supported_powertypes = (
"virsh",
"ssh",
)
@classmethod
def is_mac_valid(cls, mac):
rex = re.compile(ur'^([0-9abcdef]{2}:){5}[0-9abcdef]{2}$', re.I)
return rex.match(mac)
@classmethod
def is_os_valid(cls, os):
return os in cls._supported_os
@classmethod
def is_osversion_valid(cls, osversion):
return osversion in cls._supported_osversion
@classmethod
def is_arch_valid(cls, arch):
return arch in cls._supported_arch
@classmethod
def is_platform_valid(cls, os, osversion, arch):
return (os, osversion, arch) in cls._supported_platform
# FIXME
# IT IS NEEDED TO BE CHECKED IF PROVISION ALREADY HAS THAT PROFILE
# IF NOT THEN PROFILE IS OBVIOUSLY INVALID
@classmethod
def is_profile_valid(cls, profile):
return True
@classmethod
def is_powertype_valid(cls, powertype):
return powertype in cls._supported_powertypes
# FIXME
# IT IS NEEDED TO BE CHECKED IF POWER IS VALID
@classmethod
def is_power_valid(cls, power):
return True

View File

@ -0,0 +1,89 @@
import logging
from provision import ProvisionException
from . import ModelObject, Validator
class Node(ModelObject):
_mac = None
_profile = None
_kopts = ""
_pxe = False
_power = None
def __init__(self, name):
self.name = name
self.logger = logging.getLogger('provision.model.node')
def save(self):
self.driver.save_node(self)
@property
def mac(self):
if not self._mac:
raise ProvisionException("Mac is not set properly")
return self._mac
@mac.setter
def mac(self, mac):
if not Validator.is_mac_valid(mac):
raise ProvisionException("Mac is not valid")
self._mac = mac
@property
def profile(self):
if not self._profile:
raise ProvisionException("Profile is not set properly")
return self._profile
@profile.setter
def profile(self, profile):
if not Validator.is_profile_valid(profile):
raise ProvisionException("Profile is not valid")
self._profile = profile
@property
def kopts(self):
self.logger.debug("Node kopts getter: %s" % self._kopts)
return self._kopts
@kopts.setter
def kopts(self, kopts):
self.logger.debug("Node kopts setter: %s" % kopts)
self._kopts = kopts
@property
def pxe(self):
self.logger.debug("Node pxe getter: %s" % str(self._pxe))
return self._pxe
@pxe.setter
def pxe(self, pxe):
self.logger.debug("Node pxe setter: %s" % str(pxe))
if pxe:
self._pxe = True
else:
self._pxe = False
@property
def power(self):
if not self._power:
raise ProvisionException("Power is not set properly")
return self._power
@power.setter
def power(self, power):
if not Validator.is_power_valid(power):
raise ProvisionException("Power is not valid")
self._power = power
def power_on(self):
self.driver.power_on(self)
def power_off(self):
self.driver.power_off(self)
def power_reboot(self):
self.driver.power_reboot(self)
def power_status(self):
self.driver.power_status(self)

View File

@ -0,0 +1,52 @@
import logging
from provision import ProvisionException
from . import Validator
class Power:
_power_user = None
_power_pass = None
_power_address = None
_power_id = None
def __init__(self, power_type):
if Validator.is_powertype_valid(power_type):
self._power_type = power_type
else:
raise ProvisionException("Power type is not valid")
@property
def power_type(self):
return self._power_type
@property
def power_user(self):
return self._power_user
@power_user.setter
def power_user(self, power_user):
self._power_user = power_user
@property
def power_pass(self):
return self._power_pass
@power_pass.setter
def power_pass(self, power_pass):
self._power_pass = power_pass
@property
def power_address(self):
return self._power_address
@power_address.setter
def power_address(self, power_address):
self._power_address = power_address
@property
def power_id(self):
return self._power_id
@power_id.setter
def power_id(self, power_id):
self._power_id = power_id

View File

@ -0,0 +1,102 @@
import logging
from . import ModelObject, Validator
from provision import ProvisionException
class Profile(ModelObject):
_arch = None
_kernel = None
_initrd = None
_os = None
_osversion = None
_seed = None
_kopts = ""
def __init__(self, name):
self.name = name
self.logger = logging.getLogger('provision.model.profile')
def save(self):
if not Validator.is_platform_valid(
self._os, self._osversion, self._arch
):
raise ProvisionException("Platform is not valid")
self.driver.save_profile(self)
@property
def arch(self):
if not self._arch:
raise ProvisionException("Arch is not set properly")
return self._arch
@arch.setter
def arch(self, arch):
if not Validator.is_arch_valid(arch):
raise ProvisionException("Arch is not valid")
self._arch = arch
@property
def kernel(self):
if not self._kernel:
raise ProvisionException("Kernel is not set properly")
return self._kernel
@kernel.setter
def kernel(self, kernel):
self._kernel = kernel
@property
def initrd(self):
if not self._initrd:
raise ProvisionException("Initrd is not set properly")
return self._initrd
@initrd.setter
def initrd(self, initrd):
self._initrd = initrd
@property
def os(self):
if not self._os:
raise ProvisionException("Os is not set properly")
return self._os
@os.setter
def os(self, os):
if not Validator.is_os_valid(os):
raise ProvisionException("Os is not valid")
self._os = os
@property
def osversion(self):
if not self._osversion:
raise ProvisionException("Osversion is not set properly")
return self._osversion
@osversion.setter
def osversion(self, osversion):
if not Validator.is_osversion_valid(osversion):
raise ProvisionException("Osversion is not valid")
self._osversion = osversion
@property
def seed(self):
if not self._seed:
raise ProvisionException("Seed is not set properly")
self.logger.debug("Profile seed getter: %s" % self._seed)
return self._seed
@seed.setter
def seed(self, seed):
self.logger.debug("Profile seed setter: %s" % seed)
self._seed = seed
@property
def kopts(self):
self.logger.debug("Profile kopts getter: %s" % self._kopts)
return self._kopts
@kopts.setter
def kopts(self, kopts):
self.logger.debug("Profile kopts setter: %s" % kopts)
self._kopts = kopts

View File

@ -0,0 +1,128 @@
from model import Validator
from model.profile import Profile
from model.node import Node
from model.power import Power
from nose.tools import eq_
class TestValidator:
def setUp(self):
self.mac = "c8:0a:a9:a6:ff:28"
self.platform = ("ubuntu", "precise", "x86_64")
self.os = "ubuntu"
self.osversion = "precise"
self.arch = "x86_64"
def test_is_mac_valid(self):
assert Validator.is_mac_valid(self.mac)
def test_is_platform_valid(self):
assert Validator.is_platform_valid(
self.platform[0],
self.platform[1],
self.platform[2]
)
def test_is_os_valid(self):
assert Validator.is_os_valid(self.os)
def test_is_osversion_valid(self):
assert Validator.is_osversion_valid(self.osversion)
def test_is_arch_valid(self):
assert Validator.is_arch_valid(self.arch)
class TestProfile:
def setUp(self):
self.profile = Profile('profile')
self.arch = "x86_64"
self.os = "ubuntu"
self.osversion = "precise"
self.kernel = "kernel"
self.initrd = "initrd"
self.seed = "seed"
self.kopts = "kopts"
def test_arch(self):
self.profile.arch = self.arch
eq_(self.profile.arch, self.arch)
def test_os(self):
self.profile.os = self.os
eq_(self.profile.os, self.os)
def test_osversion(self):
self.profile.osversion = self.osversion
eq_(self.profile.osversion, self.osversion)
def test_kernel(self):
self.profile.kernel = self.kernel
eq_(self.profile.kernel, self.kernel)
def test_initrd(self):
self.profile.initrd = self.initrd
eq_(self.profile.initrd, self.initrd)
def test_seed(self):
self.profile.seed = self.seed
eq_(self.profile.seed, self.seed)
def test_kopts(self):
self.profile.kopts = self.kopts
eq_(self.profile.kopts, self.kopts)
class TestNode:
def setUp(self):
self.node = Node('node')
self.mac = "c8:0a:a9:a6:ff:28"
self.profile = Profile('profile')
self.kopts = "kopts"
self.pxe = True
self.power = Power('ssh')
def test_mac(self):
self.node.mac = self.mac
eq_(self.node.mac, self.mac)
def test_profile(self):
self.node.profile = self.profile
eq_(self.node.profile, self.profile)
def test_kopts(self):
self.node.kopts = self.kopts
eq_(self.node.kopts, self.kopts)
def test_pxe(self):
self.node.pxe = self.pxe
eq_(self.node.pxe, self.pxe)
def test_power(self):
self.node.power = self.power
eq_(self.node.power, self.power)
class TestPower:
def setUp(self):
self.power = Power('ssh')
self.power_user = "user"
self.power_pass = "pass"
self.power_address = "localhost"
self.power_id = "localhost"
def test_power_user(self):
self.power.power_user = self.power_user
eq_(self.power.power_user, self.power_user)
def test_power_pass(self):
self.power.power_pass = self.power_pass
eq_(self.power.power_pass, self.power_pass)
def test_power_address(self):
self.power.power_address = self.power_address
eq_(self.power.power_address, self.power_address)
def test_power_id(self):
self.power.power_id = self.power_id
eq_(self.power.power_id, self.power_id)

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
LOGFILE = "nailgun.log"
COBBLER_URL = "http://localhost/cobbler_api"
COBBLER_USER = "cobbler"
COBBLER_PASSWORD = "cobbler"
COBBLER_PROFILE = "centos-6.3-x86_64"

View File

@ -24,3 +24,5 @@ NETWORK_POOLS = {
NET_EXCLUDE = ['10.20.0.0/24']
VLANS = range(100, 1000)
from .extrasettings import *

View File

@ -1,16 +1,25 @@
# -*- coding: utf-8 -*-
import re
import json
from paste.fixture import TestApp
from random import randint
from unittest.case import TestCase
import re
import mock
from paste.fixture import TestApp
from sqlalchemy.orm.events import orm
from api.models import engine, Node, Release, Cluster, Role
from api.urls import urls
from db import dropdb, syncdb, flush
from manage import app
from db import dropdb, syncdb, flush
class BaseHandlers(TestCase):
def __init__(self, *args, **kwargs):
super(BaseHandlers, self).__init__(*args, **kwargs)
self.mock = mock
@classmethod
def setUpClass(cls):
dropdb()
@ -31,6 +40,10 @@ class BaseHandlers(TestCase):
'memory': 'a'}
return metadata
def _generate_random_mac(self):
mac = [randint(0x00, 0x7f) for _ in xrange(6)]
return ':'.join(map(lambda x: "%02x" % x, mac))
def create_release_api(self):
resp = self.app.post(
'/api/releases',
@ -45,7 +58,7 @@ class BaseHandlers(TestCase):
def create_default_node(self):
node = Node()
node.mac = u"ASDFGHJKLMNOPR"
node.mac = self._generate_random_mac()
self.db.add(node)
self.db.commit()
return node

View File

@ -1,16 +0,0 @@
import json
from base import BaseHandlers
from base import reverse
class TestClusterChangesHandler(BaseHandlers):
def test_cluster_starts_deploy(self):
cluster = self.create_default_cluster()
resp = self.app.put(
reverse(
'ClusterChangesHandler',
kwargs={'cluster_id': cluster.id}),
headers=self.default_headers
)
self.assertEquals(200, resp.status)

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import unittest
import json

View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
import json
import logging
import unittest
from settings import settings
from base import BaseHandlers
from base import reverse
from provision import ProvisionConfig
from provision import ProvisionFactory
from provision.model.profile import Profile as ProvisionProfile
from provision.model.node import Node as ProvisionNode
from provision.model.power import Power as ProvisionPower
class TestProvisioning(BaseHandlers):
def test_nodes_in_cluster(self):
cluster = self.create_default_cluster()
node = self.create_default_node()
node2 = self.create_default_node()
node2.status = "discover"
node3 = self.create_default_node()
cluster.nodes.append(node)
cluster.nodes.append(node2)
self.db.add(cluster)
self.db.commit()
self.assertEqual(len(cluster.nodes), 2)
ProvisionFactory.getInstance = self.mock.MagicMock()
resp = self.app.put(
reverse(
'ClusterChangesHandler',
kwargs={"cluster_id": cluster.id}
),
"",
headers=self.default_headers,
expect_errors=True
)
self.assertEquals(200, resp.status)

View File

@ -4,8 +4,8 @@
"description": "Description for Release",
"networks_metadata": [
{"name": "floating", "access": "public"},
{"name": "admin", "access": "private"},
{"name": "storage", "access": "private"}
{"name": "admin", "access": "private10"},
{"name": "storage", "access": "private172"}
],
"roles": [
{