2013-05-03 14:00:57 +02:00

245 lines
7.9 KiB
Python

# coding=utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2012, Intel Performance Learning Solutions Ltd.
#
# 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.
"""
The compute resource backend for OpenStack.
"""
#pylint: disable=W0232,R0201
import random
from occi import backend
from occi import exceptions
from occi_os_api.extensions import os_addon
from occi_os_api.nova_glue import vm
from occi_os_api.nova_glue import security
class OsComputeBackend(backend.MixinBackend, backend.ActionBackend):
"""
The OpenStackCompute backend.
"""
def retrieve(self, entity, extras):
"""
Add OpenStack related actions.
"""
uid = entity.attributes['occi.core.id']
context = extras['nova_ctx']
# set additional actions
if 'occi.compute.state' in entity.attributes and entity.attributes[
'occi.compute.state'] == 'active':
entity.actions.append(os_addon.OS_CREATE_IMAGE)
entity.actions.append(os_addon.OS_CHG_PWD)
# add VNC link if available
console = vm.get_vnc(uid, context)
if console:
entity.attributes['org.openstack.compute.console.vnc'] =\
console['url']
else:
entity.attributes['org.openstack.compute.console.vnc'] = 'N/A'
# also expose the exact openstack state
entity.attributes['org.openstack.compute.state'] = \
vm.get_vm(uid, context)['vm_state']
def action(self, entity, action, attributes, extras):
"""
This is called by pyssf when an action request is issued.
"""
context = extras['nova_ctx']
uid = entity.attributes['occi.core.id']
if action == os_addon.OS_CHG_PWD:
if 'org.openstack.credentials.admin_pwd' not in attributes:
msg = 'org.openstack.credentials.admin_pwd was not supplied'\
' in the request.'
raise AttributeError(msg)
new_password = attributes['org.openstack.credentials.admin_pwd']
vm.set_password_for_vm(uid, new_password, context)
elif action == os_addon.OS_CREATE_IMAGE:
if 'org.openstack.snapshot.image_name' not in attributes:
raise AttributeError('Missing image name')
image_name = attributes['org.openstack.snapshot.image_name']
vm.snapshot_vm(uid, image_name, context)
else:
raise AttributeError('Not an applicable action.')
class OsNetLinkBackend(backend.MixinBackend, backend.ActionBackend):
"""
The OpenStack network link backend.
"""
pass
class SecurityGroupBackend(backend.UserDefinedMixinBackend):
"""
Security Group backend.
"""
def init_sec_group(self, category, extras):
"""
Creates the security group as specified in the request.
"""
#do not recreate default openstack security groups
if category.scheme == \
'http://schemas.openstack.org/infrastructure/security/group#':
return
context = extras['nova_ctx']
group_name = category.term.strip()
group_description = (category.title.strip()
if category.title else group_name)
security.create_group(group_name, group_description, context)
def destroy(self, category, extras):
"""
Deletes the specified security group.
"""
context = extras['nova_ctx']
security_group = security.retrieve_group(category.term,
extras['nova_ctx'])
security.remove_group(security_group.id, context)
class SecurityRuleBackend(backend.KindBackend):
"""
Security rule backend.
"""
def create(self, entity, extras):
"""
Creates a security rule.
The group to add the rule to must exist.
In OCCI-speak this means the mixin must be supplied with the request
"""
sec_mixin = get_sec_mixin(entity)
context = extras['nova_ctx']
security_group = security.retrieve_group(sec_mixin.term,
context)
sg_rule = make_sec_rule(entity, security_group['id'])
if security_group_rule_exists(security_group, sg_rule):
#This rule already exists in group
msg = 'This rule already exists in group. %s' %\
str(security_group)
raise AttributeError(msg)
security.create_rule(sg_rule, context)
def delete(self, entity, extras):
"""
Deletes the security rule.
"""
try:
context = extras['nova_ctx']
rule = security.retrieve_rule(entity.attributes['occi.core.id'],
context)
security.remove_rule(rule, context)
except Exception as error:
raise exceptions.HTTPError(500, str(error))
def make_sec_rule(entity, sec_grp_id):
"""
Create and validate the security rule.
"""
name = random.randrange(0, 99999999)
sg_rule = {'id': name,
'parent_group_id': sec_grp_id}
entity.attributes['occi.core.id'] = str(sg_rule['id'])
prot = \
entity.attributes['occi.network.security.protocol'].lower().strip()
if prot in ('tcp', 'udp', 'icmp'):
sg_rule['protocol'] = prot
else:
raise AttributeError('Invalid protocol defined:' + prot)
from_p = entity.attributes['occi.network.security.to'].strip()
from_p = int(from_p)
if (type(from_p) is int) and 0 < from_p <= 65535:
sg_rule['from_port'] = from_p
else:
raise AttributeError('No valid from port defined.')
to_p = entity.attributes['occi.network.security.to'].strip()
to_p = int(to_p)
if (type(to_p) is int) and 0 < to_p <= 65535:
sg_rule['to_port'] = to_p
else:
raise AttributeError('No valid to port defined.')
if from_p > to_p:
raise AttributeError('From port is bigger than to port defined.')
cidr = entity.attributes['occi.network.security.range'].strip()
if len(cidr) <= 0:
cidr = '0.0.0.0/0'
if True:
sg_rule['cidr'] = cidr
else:
raise AttributeError('No valid CIDR defined.')
sg_rule['group'] = {}
return sg_rule
def get_sec_mixin(entity):
"""
Get the security mixin of the supplied entity.
"""
sec_mixin_present = 0
sec_mixin = None
for mixin in entity.mixins:
if os_addon.SEC_GROUP in mixin.related:
sec_mixin = mixin
sec_mixin_present += 1
if not sec_mixin_present:
# no mixin of the type security group was found
msg = 'No security group mixin was found'
raise AttributeError(msg)
if sec_mixin_present > 1:
msg = 'More than one security group mixin was found'
raise AttributeError(msg)
return sec_mixin
def security_group_rule_exists(security_group, values):
"""
Indicates whether the specified rule values are already
defined in the given security group.
"""
# Taken directly from security_groups.py as that method is not
# directly import-able.
for rule in security_group['rules']:
is_duplicate = True
keys = ('group_id', 'cidr', 'from_port', 'to_port', 'protocol')
for key in keys:
if rule.get(key) != values.get(key):
is_duplicate = False
break
if is_duplicate:
return True
return False