Added implementation for Delete Node Task

* added unit tests for delete node task
* updated BaseFixture class for unit test mocking to accept either
  a string to class to mock or class type directly
* added mock code for nova client create vm, list vms and delete vm

Change-Id: I7ad9e29a2ce1c4e73efc6dce84146537731cc87b
This commit is contained in:
dagnello 2015-02-05 10:48:10 -08:00
parent 03760edabb
commit 90628ad709
6 changed files with 306 additions and 5 deletions

View File

@ -21,9 +21,9 @@ import novaclient.client as NovaClient
def nova_client():
return NovaClient.Client(2,
'admin',
'secrete',
'messina',
'demo',
'http://192.168.41.183:5000/v2.0'
'http://192.168.131.136:5000/v2.0'
)

View File

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
import uuid
from cue import client
from cue.tests import base
from cue.tests.test_fixtures import nova
import os_tasklib.nova.delete_vm as delete_vm
from taskflow import engines
from taskflow.patterns import linear_flow
SHARED_CONF = {
'connection': 'zookeeper',
}
class DeleteVmTests(base.TestCase):
additional_fixtures = [
nova.NovaClient
]
task_store = {
'vm_id': "0",
}
def setUp(self):
super(DeleteVmTests, self).setUp()
# retrieve neutron client API class
self.nova_client = client.nova_client()
# create flow with "DeleteVm" task
self.flow = linear_flow.Flow('create port').add(delete_vm.DeleteVm(
os_client=self.nova_client))
self.image = self.nova_client.images.find(
name="cirros-0.3.2-x86_64-uec-kernel")
self.flavor = self.nova_client.flavors.find(name="m1.tiny")
def test_delete_vm_invalid_id(self):
# create a few vms
new_instances = [self.nova_client.servers.create(name="vm1",
image=self.image,
flavor=self.flavor),
self.nova_client.servers.create(name="vm2",
image=self.image,
flavor=self.flavor),
self.nova_client.servers.create(name="vm3",
image=self.image,
flavor=self.flavor)]
# delete non-existing vm (invalid id)
DeleteVmTests.task_store['vm_id'] = uuid.uuid4()
# start engine to run delete task
engines.run(self.flow, store=DeleteVmTests.task_store)
# verify our existing vms have not been deleted
vms = self.nova_client.servers.list()
found = 0
for vm in vms:
for created_vm in new_instances:
if vm.id == created_vm.id:
found += 1
# cleanup
for vm in new_instances:
self.nova_client.servers.delete(vm)
self.assertEqual(len(new_instances), found, "Not all VMs were found")
def test_delete_vm(self):
# create a few vms
image = self.nova_client.images.find(
name="cirros-0.3.2-x86_64-uec-kernel")
flavor = self.nova_client.flavors.find(name="m1.tiny")
new_instances = [self.nova_client.servers.create(name="vm1",
image=image,
flavor=flavor),
self.nova_client.servers.create(name="vm2",
image=image,
flavor=flavor),
self.nova_client.servers.create(name="vm3",
image=image,
flavor=flavor)]
# delete one vm
vm_to_delete = new_instances.pop()
DeleteVmTests.task_store['vm_id'] = vm_to_delete.id
# start engine to run delete task
engines.run(self.flow, store=DeleteVmTests.task_store)
# verify vm has been deleted
vms = self.nova_client.servers.list()
vm_found = False
for vm in vms:
if vm.id == vm_to_delete.id:
vm_found = True
break
# cleanup
for vm in new_instances:
self.nova_client.servers.delete(vm)
self.assertEqual(False, vm_found, "VM was not deleted successfully")

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import inspect
import fixtures
import mock
@ -51,7 +53,15 @@ class BaseFixture(fixtures.Fixture):
:param cls: Class to be mock'd. Pass in the string path to the class.
:return: A mock'd version of the class.
"""
patch = mock.patch(cls)
class_name = ''
if isinstance(cls, str):
class_name = cls
elif inspect.isclass(cls):
class_name = "%s.%s" % (cls.__module__, cls.__name__)
else:
raise TypeError('Invalid parameter type provided')
patch = mock.patch(class_name)
mock_instance = patch.__enter__()
self.addCleanup(patch.__exit__)
mocked_cls = mock_instance.return_value

View File

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
import uuid
import novaclient.v1_1.client as nova_client
import cue.tests.test_fixtures.base as base
class VmDetails():
def __init__(self, vm_id, name, flavor):
self.id = vm_id
self.name = name
self.flavor = flavor
class NovaClient(base.BaseFixture):
"""A test fixture to simulate a Nova Client connection
This class is used in test cases to simulate a real Nova Client
connection in the absence of a working Neutron API endpoint.
"""
def setUp(self):
"""Set up test fixture and apply all method overrides."""
super(NovaClient, self).setUp()
self._vm_list = {}
self._flavor_id = 1
self._image_id = 1
self._image_name = ""
self._flavor_name = ""
v2_client = self.mock(nova_client.Client)
v2_client.servers.create = self.create_vm
v2_client.servers.delete = self.delete_vm
v2_client.servers.list = self.list_vms
v2_client.flavors.find = self.flavors_find
v2_client.images.find = self.image_find
def flavors_find(self, name=None):
"""Mock'd version of novaclient...flavors_find().
Finds a flavor ID based on provided name.
:param name: Flavor name.
:return: Flavor ID matching provided flavor name.
"""
self._flavor_name = name
return self._flavor_id
def image_find(self, name=None):
"""Mock'd version of novaclient...image_find().
Finds a
:param name: Image name.
:return: Image ID matching provided image name.
"""
self._image_name = name
return self._image_id
def create_vm(self, **kwargs):
"""Mock'd version of novaclient...create_vm().
Create a Nova VM.
:param body: Dictionary with vm information.
:return: An updated copy of the 'body' that was passed in, with other
information populated.
"""
if 'name' in kwargs:
vm_name = kwargs['name']
else:
vm_name = "new_vm"
if 'flavor' in kwargs:
vm_flavor = kwargs['flavor']
else:
vm_flavor = "medium"
newVm = VmDetails(vm_id=uuid.uuid4(), name=vm_name, flavor=vm_flavor)
self._vm_list[newVm.id] = newVm
return newVm
def delete_vm(self, vm_id):
"""Mock'd version of novaclient...delete_vm().
:param vm object with id instance variable
:return: n/a
"""
if vm_id in self._vm_list:
del(self._vm_list[vm_id])
def list_vms(self, retrieve_all=True, **kwargs):
"""Mock'd version of novaclient...list_vms().
List available vms.
:param retrieve_all: Set to true to retrieve all available ports
"""
if retrieve_all:
return self._vm_list.values()

View File

@ -17,9 +17,24 @@ import os_tasklib
class CreatePort(os_tasklib.BaseTask):
"""CreatePort Task
This task interfaces with Neutron API and creates a port based on the
parameters provided to the Task.
"""
default_provides = 'neutron_port_id'
def execute(self, network_id, port_name, **kwargs):
"""Main execute method
:param network_id: Network id to connect new port to
:type network_id: string
:param port_name: Name for new port
:type port_name: string
:return: Port record provided by Neutron
:rtype: dict
"""
body_value = {
"port": {
"admin_state_up": True,
@ -29,9 +44,8 @@ class CreatePort(os_tasklib.BaseTask):
}
port = self.os_client.create_port(body=body_value)
port_id = port['port']['id']
return port_id
return port
def revert(self, **kwargs):
"""Revert function for a failed create port task."""

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
import os_tasklib
from cue.common.i18n import _LI # noqa
from cue.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class DeleteVm(os_tasklib.BaseTask):
"""DeleteVm Task
This task interfaces with Nova API and deletes a VM identified by the
VM ID provided to the Task.
"""
def execute(self, vm_id, **kwargs):
"""Main execute method
:param vm_id: Network id to connect new port to
:type vm_id: string
:return: n/a
"""
self.os_client.servers.delete(vm_id)
LOG.info(_LI('Deleting VM, id: %s') % vm_id)