Commit 315d835a authored by Efi's avatar Efi

Merge pull request #20 from makistsantekidis/kamaki-api-vm-provision

LAM-38 First implementation of vm provisioning
parents 78734435 8ebb23a5
......@@ -60,3 +60,4 @@ docs/_build/
target/
ansible/hosts
MANIFEST
__author__ = 'mike'
from __future__ import (absolute_import, division,
print_function, unicode_literals)
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
from kamaki.clients import astakos, cyclades
from kamaki.clients import ClientError
from kamaki.clients.utils import https
from kamaki.cli.config import Config as KamakiConfig
# TODO: remove this and actually use ssl cert files
https.patch_ignore_ssl()
import argparse
storage_templates = ['drdb', 'ext_vlmc']
class Provisioner:
"""
provisions virtual machines on ~okeanos
"""
def __init__(self, cloud_name):
# Load .kamakirc configuration
logger.info("Retrieving .kamakirc configuration")
self.config = KamakiConfig()
cloud_section = self.config._sections['cloud'].get(cloud_name)
if not cloud_section:
message = "Cloud '%s' was not found in you .kamakirc configuration file. " \
"Currently you have availablie in your configuration these clouds: %s"
raise KeyError(message % (cloud_name, self.config._sections['cloud'].keys()))
# Get the authentication url and token
auth_url, auth_token = cloud_section['url'], cloud_section['token']
logger.info("Initiating Astakos Client")
self.astakos = astakos.AstakosClient(auth_url, auth_token)
logger.info("Retrieving cyclades endpoint url")
compute_url = self.astakos.get_endpoint_url(
cyclades.CycladesComputeClient.service_type)
logger.info("Initiating Cyclades client")
self.cyclades = cyclades.CycladesComputeClient(compute_url, auth_token)
def find_flavor(self, **kwargs):
"""
:param kwargs: should contains the keys that specify the specs
:return: first flavor objects that matches the specs criteria
"""
# Set all the default parameters
kwargs.setdefault("vcpus", 1)
kwargs.setdefault("ram", 1024)
kwargs.setdefault("disk", 40)
logger.info("Retrieving flavor")
for flavor in self.cyclades.list_flavors(detail=True):
if all([kwargs[key] == flavor[key] \
for key in set(flavor.keys()).intersection(kwargs.keys())]):
return flavor
return None
def find_image(self, **kwargs):
"""
:param image_name: Name of the image to filter by
:param kwargs:
:return: first image object that matches the name criteria
"""
image_name = kwargs['image_name']
logger.info("Retrieving image")
for image in self.cyclades.list_images(detail=True):
if image_name in image['name']:
return image
return None
def find_project_id(self, **kwargs):
"""
:param kwargs: name, state, owner and mode to filter project by
:return: first project_id that matches the project name
"""
filter = {
'name': kwargs.get("project_name"),
'state': kwargs.get("project_state"),
'owner': kwargs.get("project_owner"),
'mode': kwargs.get("project_mode"),
}
logger.info("Retrieving project")
return self.astakos.get_projects(**filter)[0]
def create_vm(self, vm_name=None, **kwargs):
"""
:param vm_name: Name of the virtual machine to create
:param kwargs: passed to the functions called for detail options
:return:
"""
flavor_id = self.find_flavor(**kwargs)['id']
image_id = self.find_image(**kwargs)['id']
project_id = self.find_project_id(**kwargs)['id']
try:
okeanos_response = self.cyclades.create_server(name=vm_name, flavor_id=flavor_id,
image_id=image_id,
project_id=project_id,
networks=[], personality=[])
except ClientError as ex:
raise ex
return okeanos_response
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Okeanos VM provisioning")
parser.add_argument('--cloud', type=str, dest="cloud", default="lambda")
parser.add_argument('--project-name', type=str, dest="project_name",
default="lambda.grnet.gr")
parser.add_argument('--name', type=str, dest='name', default="to mikro debian sto livadi")
args = parser.parse_args()
provisioner = Provisioner(cloud_name=args.cloud)
print(provisioner.create_vm(vm_name=args.name, project_name=args.project_name,
image_name="debian"))
kamaki
\ No newline at end of file
from distutils.core import setup
setup(
name='Fokia',
version='0.0.1',
packages=['fokia'],
url='https://github.com/grnet/okeanos-LoD',
license='',
author='',
author_email='',
description='~okeanos Lambda on Demand project',
)
import mock
from fokia.provisioner import Provisioner
test_flavors = [{u'SNF:allow_create': True,
u'SNF:disk_template': u'drbd',
u'SNF:volume_type': 1,
u'disk': 20,
u'id': 1,
u'links': [{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/1',
u'rel': u'self'},
{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/1',
u'rel': u'bookmark'}],
u'name': u'C1R1024D20drbd',
u'ram': 1024,
u'vcpus': 1},
{u'SNF:allow_create': True,
u'SNF:disk_template': u'drbd',
u'SNF:volume_type': 1,
u'disk': 40,
u'id': 3,
u'links': [{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/3',
u'rel': u'self'},
{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/3',
u'rel': u'bookmark'}],
u'name': u'C1R1024D40drbd',
u'ram': 1024,
u'vcpus': 1},
{u'SNF:allow_create': True,
u'SNF:disk_template': u'drbd',
u'SNF:volume_type': 1,
u'disk': 20,
u'id': 4,
u'links': [{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/4',
u'rel': u'self'},
{u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/flavors/4',
u'rel': u'bookmark'}],
u'name': u'C1R2048D20drbd',
u'ram': 2048,
u'vcpus': 1}]
test_images = [{u'created': u'2015-06-26T11:29:59+00:00',
u'id': u'0035ac89-a86e-4108-93e8-93e294b74a3d',
u'is_snapshot': False,
u'links': [{
u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/images/0035ac89-a86e-4108-93e8-93e294b74a3d',
u'rel': u'self'},
{
u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/images/0035ac89-a86e-4108-93e8-93e294b74a3d',
u'rel': u'bookmark'},
{
u'href': u'https://cyclades.okeanos.grnet.gr/image/v1.0/images/0035ac89-a86e-4108-93e8-93e294b74a3d',
u'rel': u'alternate'}],
u'metadata': {
u'description': u'ArchLinux 2015.06.26 with openssh and iptables setup - accepting only PubKeyAuth',
u'gui': u'No GUI',
u'kernel': u'4.0.6-1',
u'os': u'archlinux',
u'osfamily': u'linux',
u'partition_table': u'gpt',
u'root_partition': u'1',
u'sortorder': u'7400000',
u'users': u'root'},
u'name': u'archlinux-2015.06.26',
u'progress': 100,
u'public': True,
u'status': u'ACTIVE',
u'tenant_id': u'7e271a0b-1427-45ec-9916-f8e72bfbf3d4',
u'updated': u'2015-06-26T11:29:59+00:00',
u'user_id': u'7e271a0b-1427-45ec-9916-f8e72bfbf3d4'},
{u'created': u'2014-03-11T12:55:07+00:00',
u'id': u'0099593e-4f6d-48bf-8f03-0cec7fabb05b',
u'is_snapshot': False,
u'links': [{
u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/images/0099593e-4f6d-48bf-8f03-0cec7fabb05b',
u'rel': u'self'},
{
u'href': u'https://cyclades.okeanos.grnet.gr/compute/v2.0/images/0099593e-4f6d-48bf-8f03-0cec7fabb05b',
u'rel': u'bookmark'},
{
u'href': u'https://cyclades.okeanos.grnet.gr/image/v1.0/images/0099593e-4f6d-48bf-8f03-0cec7fabb05b',
u'rel': u'alternate'}],
u'metadata': {u'description': u'Master clone',
u'os': u'ubuntu',
u'osfamily': u'linux',
u'partition_table': u'msdos',
u'root_partition': u'1',
u'users': u'user hduser'},
u'name': u'master_clone',
u'progress': 100,
u'public': True,
u'status': u'ACTIVE',
u'tenant_id': u'607bc20e-ae01-46ca-8a7d-d37b92e9908f',
u'updated': u'2014-03-11T12:55:07+00:00',
u'user_id': u'607bc20e-ae01-46ca-8a7d-d37b92e9908f'}]
test_projects = [{u'creation_date': u'2015-06-09T09:46:44.327826+00:00',
u'description': u'',
u'end_date': u'2015-11-30T00:00:00+00:00',
u'homepage': u'',
u'id': u'6ff62e8e-0ce9-41f7-ad99-13a18ecada5f',
u'join_policy': u'moderated',
u'leave_policy': u'auto',
u'max_members': 9223372036854775807,
u'name': u'lambda.grnet.gr',
u'owner': u'69c6686c-4e3e-407e-96b4-c21ef7d5def5',
u'private': False,
u'resources': {u'astakos.pending_app': {u'member_capacity': 0,
u'project_capacity': 0},
u'cyclades.cpu': {u'member_capacity': 80,
u'project_capacity': 80},
u'cyclades.disk': {u'member_capacity': 1073741824000,
u'project_capacity': 1073741824000},
u'cyclades.floating_ip': {u'member_capacity': 10,
u'project_capacity': 10},
u'cyclades.network.private': {u'member_capacity': 5,
u'project_capacity': 5},
u'cyclades.ram': {u'member_capacity': 128849018880,
u'project_capacity': 128849018880},
u'cyclades.vm': {u'member_capacity': 20,
u'project_capacity': 20},
u'pithos.diskspace': {u'member_capacity': 0,
u'project_capacity': 0}},
u'state': u'active',
u'system_project': False}]
def test_find_flavor():
with mock.patch('fokia.provisioner.astakos'), \
mock.patch('fokia.provisioner.KamakiConfig'), \
mock.patch('fokia.provisioner.cyclades'):
provisioner = Provisioner("lambda")
provisioner.astakos.get_projects.return_value = test_projects
provisioner.cyclades.list_images.return_value = test_images
provisioner.cyclades.list_flavors.return_value = test_flavors
provisioner.create_vm(vm_name="tost", project_name="lambda.grnet.gr",
project_mode="supahpower", image_name="archlinux")
provisioner.cyclades.create_server.assert_called_with(
name='tost', image_id=u'0035ac89-a86e-4108-93e8-93e294b74a3d', flavor_id=3,
project_id=u'6ff62e8e-0ce9-41f7-ad99-13a18ecada5f', networks=[], personality=[])
if __name__ == "__main__":
test_find_flavor()
[tox]
envlist = py27
[testenv]
deps=
pytest
mock
-rrequirements.txt
commands=
pip install six
py.test
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment