Update nova driver to Platform9 2.4 release
This commit updates the nova driver to latest release of Platform9. Some of the notable changes include: 1. Addition of unit tests 2. Configurable maximum usable resources i.e. memory, disk and cpu 3. Better integration for security groups with latest changes in neutron
This commit is contained in:
parent
db31845d4c
commit
2e684990f3
5
nova/CHANGELOG
Normal file
5
nova/CHANGELOG
Normal file
@ -0,0 +1,5 @@
|
||||
12th December 2016:
|
||||
a. Adds unit tests
|
||||
b. Adds additional configurable settings for configuring maximum resources available to nova
|
||||
c. Better security group integration with latest changes in neutron drivers
|
||||
|
@ -1,5 +1,8 @@
|
||||
## Setup
|
||||
|
||||
Updated: 12th December 2016
|
||||
(Updated to be in sync with Platform9 release 2.4)
|
||||
|
||||
### Prerequesites
|
||||
1. Working green field OpenStack deployment (code currently based out of stable/liberty)
|
||||
2. The virtualenv used by nova should have Amazon boto package installed
|
||||
@ -9,15 +12,27 @@
|
||||
|
||||
### Instructions
|
||||
1. Copy the nova/ec2 directory to <nova-root>/nova/nova/virt/
|
||||
2. Update the configuration files -
|
||||
1. edit /etc/nova/**nova.conf**
|
||||
2. Update the configuration files -
|
||||
1. edit /etc/nova/**nova.conf**
|
||||
```
|
||||
[DEFAULT]
|
||||
compute_driver = ec2.EC2Driver
|
||||
|
||||
|
||||
[AWS]
|
||||
secret_key = <your aws secret access key>
|
||||
access_key = <your aws access key>
|
||||
region_name = <was region to use>
|
||||
max_cpus = <maximum CPUs that nova should use (default: 500)>
|
||||
max_memory_mb = <maximum memory that nova should use (default: 102400 i.e. 1000GB)>
|
||||
max_disk_gb = <maximum storage that nova should use (default: 1024 i.e. 1 TB)>
|
||||
```
|
||||
3. Restart the nova compute services
|
||||
|
||||
### Running unit tests:
|
||||
1. Copy the nova/tests/ec2 to <nova-root>/nova/tests/unit/virt directory
|
||||
2. To run the AWS Driver unit tests -
|
||||
```
|
||||
tox -e <env> nova.tests.unit.virt.ec2
|
||||
e.g. to run python 2.7 tests -
|
||||
tox -e py27 nova.tests.unit.virt.ec2
|
||||
```
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class EC2GroupTransformer:
|
||||
|
||||
def to_group(self, ec2_group):
|
||||
pass
|
@ -1,25 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class EC2RuleService:
|
||||
|
||||
def __init__(self, ec2_connection, ec2_rule_transformer):
|
||||
self.ec2_connection = ec2_connection
|
||||
self.ec2_rule_transformer = ec2_rule_transformer
|
||||
|
||||
def get_rules_for_group(self, group_name):
|
||||
group = self.ec2_connection.get_all_security_groups(groupnames=group_name)[0]
|
||||
return set([self.ec2_rule_transformer.to_rule(rule) for rule in group.rules])
|
@ -1,38 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from copy import deepcopy
|
||||
from rule import Rule
|
||||
|
||||
|
||||
class EC2RuleTransformer:
|
||||
|
||||
def __init__(self, ec2_connection):
|
||||
self.ec2_connection = ec2_connection
|
||||
|
||||
def to_rule(self, ec2_rule):
|
||||
rule_args = {}
|
||||
rule_args['ip_protocol'] = ec2_rule.ip_protocol
|
||||
rule_args['from_port'] = ec2_rule.from_port
|
||||
rule_args['to_port'] = ec2_rule.to_port
|
||||
|
||||
if ec2_rule.grants[0].cidr_ip:
|
||||
rule_args['ip_range'] = ec2_rule.grants[0].cidr_ip
|
||||
else:
|
||||
group_id = ec2_rule.grants[0].group_id
|
||||
rule_args['group_name'] = self.ec2_connection.get_all_security_groups(group_ids=group_id)[0].name
|
||||
|
||||
return Rule(**rule_args)
|
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,3 @@
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
#
|
||||
# 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 expressed or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from nova import exception
|
||||
|
||||
@ -28,4 +14,4 @@ class Ec2ExceptionHandler:
|
||||
elif ec2_response_error_exc.error_code == "InvalidAMIID.NotFound":
|
||||
return exception.ImageNotFoundEC2("Invalid Image")
|
||||
else:
|
||||
return exception.NovaException(ec2_response_error_exc.message)
|
||||
return exception.NovaException(ec2_response_error_exc.message)
|
@ -1,20 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class Group:
|
||||
|
||||
def rule_diff(self, other_group):
|
||||
pass
|
@ -1,55 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class GroupRuleRefresher:
|
||||
|
||||
def __init__(self, ec2_connection, openstack_rule_service, ec2_rule_service):
|
||||
self.ec2_conn = ec2_connection
|
||||
self.openstack_rule_service = openstack_rule_service
|
||||
self.ec2_rule_service = ec2_rule_service
|
||||
|
||||
def refresh(self, group_name):
|
||||
openstack_rules = self.openstack_rule_service.get_rules_for_group(group_name)
|
||||
ec2_rules = self.ec2_rule_service.get_rules_for_group(group_name)
|
||||
|
||||
self._add_rules_to_ec2(ec2_rules, group_name, openstack_rules)
|
||||
self._remove_rules_from_ec2(ec2_rules, group_name, openstack_rules)
|
||||
|
||||
def _add_rules_to_ec2(self, ec2_rules, group_name, openstack_rules):
|
||||
for rule in openstack_rules - ec2_rules:
|
||||
self._add_rule_on_ec2(group_name, rule)
|
||||
|
||||
def _remove_rules_from_ec2(self, ec2_rules, group_name, openstack_rules):
|
||||
for rule in ec2_rules - openstack_rules:
|
||||
self._remove_rule_from_ec2(group_name, rule)
|
||||
|
||||
def _remove_rule_from_ec2(self, group_name, rule):
|
||||
self.ec2_conn.revoke_security_group(
|
||||
group_name=group_name,
|
||||
ip_protocol=rule.ip_protocol,
|
||||
from_port=rule.from_port,
|
||||
to_port=rule.to_port,
|
||||
cidr_ip=rule.ip_range
|
||||
)
|
||||
|
||||
def _add_rule_on_ec2(self, group_name, rule):
|
||||
self.ec2_conn.authorize_security_group(
|
||||
group_name=group_name,
|
||||
ip_protocol=rule.ip_protocol,
|
||||
from_port=rule.from_port,
|
||||
to_port=rule.to_port,
|
||||
cidr_ip=rule.ip_range
|
||||
)
|
@ -1,27 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class InstanceRuleRefresher:
|
||||
|
||||
def __init__(self, group_rule_refresher):
|
||||
self.group_rule_refresher = group_rule_refresher
|
||||
|
||||
def refresh(self, instance):
|
||||
for group_name in self._get_group_names(instance):
|
||||
self.group_rule_refresher.refresh(group_name)
|
||||
|
||||
def _get_group_names(self, instance):
|
||||
return [group['name'] for group in instance.security_groups]
|
@ -1,23 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class OpenstackGroupService():
|
||||
|
||||
def __init__(self, security_group_manager):
|
||||
self.security_group_manager = security_group_manager
|
||||
|
||||
def get_group(self, group_name):
|
||||
return [group for group in self.security_group_manager.list() if group.name == group_name][0]
|
@ -1,19 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class OpenstackGroupTransformer:
|
||||
def to_group(self, openstack_group):
|
||||
pass
|
@ -1,25 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class OpenstackRuleService:
|
||||
def __init__(self, group_service, openstack_rule_transformer):
|
||||
self.group_service = group_service
|
||||
self.openstack_rule_transformer = openstack_rule_transformer
|
||||
|
||||
def get_rules_for_group(self, group_name):
|
||||
openstack_group = self.group_service.get_group(group_name)
|
||||
return set([self.openstack_rule_transformer.to_rule(rule) for rule in openstack_group.rules])
|
||||
# return self.group_service.get_group(group_name).rules
|
@ -1,33 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from copy import deepcopy
|
||||
from rule import Rule
|
||||
|
||||
|
||||
class OpenstackRuleTransformer:
|
||||
def to_rule(self, openstack_rule):
|
||||
rule_args = {}
|
||||
rule_args['ip_protocol'] = openstack_rule['ip_protocol']
|
||||
rule_args['from_port'] = str(openstack_rule['from_port'])
|
||||
rule_args['to_port'] = str(openstack_rule['to_port'])
|
||||
|
||||
if 'cidr' in openstack_rule['ip_range']:
|
||||
rule_args['ip_range'] = openstack_rule['ip_range']['cidr']
|
||||
else:
|
||||
rule_args['group_name'] = openstack_rule['group']['name']
|
||||
|
||||
return Rule(**rule_args)
|
@ -1,32 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class Rule:
|
||||
def __init__(self, ip_protocol, from_port, to_port, ip_range=None, group_name=None):
|
||||
self.ip_protocol = ip_protocol
|
||||
self.from_port = from_port
|
||||
self.to_port = to_port
|
||||
self.ip_range = ip_range
|
||||
self.group_name = group_name
|
||||
|
||||
def __key(self):
|
||||
return self.ip_protocol, self.from_port, self.to_port, self.ip_range, self.group_name
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__key() == other.__key()
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__key())
|
@ -1,47 +0,0 @@
|
||||
# Copyright (c) 2014 ThoughtWorks
|
||||
# Copyright (c) 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
class RuleComparator:
|
||||
def __init__(self, ec2_connection):
|
||||
self.ec2_connection = ec2_connection
|
||||
|
||||
def rules_are_equal(self, openstack_rule, ec2_rule):
|
||||
if self._ip_protocols_are_different(ec2_rule, openstack_rule) \
|
||||
or self._from_ports_are_different(ec2_rule, openstack_rule) \
|
||||
or self._to_ports_are_different(ec2_rule, openstack_rule) \
|
||||
or self._ip_ranges_are_present_and_different(ec2_rule, openstack_rule) \
|
||||
or self._group_names_are_present_and_different(openstack_rule, ec2_rule):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _ip_protocols_are_different(self, ec2_rule, openstack_rule):
|
||||
return openstack_rule['ip_protocol'] != ec2_rule.ip_protocol
|
||||
|
||||
def _from_ports_are_different(self, ec2_rule, openstack_rule):
|
||||
return str(openstack_rule['from_port']) != ec2_rule.from_port
|
||||
|
||||
def _to_ports_are_different(self, ec2_rule, openstack_rule):
|
||||
return str(openstack_rule['to_port']) != ec2_rule.to_port
|
||||
|
||||
def _ip_ranges_are_present_and_different(self, ec2_rule, openstack_rule):
|
||||
return ('cidr' in openstack_rule['ip_range'] and openstack_rule['ip_range']['cidr'] != ec2_rule.grants[0].cidr_ip)
|
||||
|
||||
def _group_names_are_present_and_different(self, openstack_rule, ec2_rule):
|
||||
if 'name' not in openstack_rule['group']:
|
||||
return False
|
||||
else:
|
||||
ec2_group_name = self.ec2_connection.get_all_security_groups(group_ids=ec2_rule.grants[0].group_id)[0].name
|
||||
return openstack_rule['group']['name'] != ec2_group_name
|
1
nova/test-requirements.txt
Normal file
1
nova/test-requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
moto
|
0
nova/tests/ec2/__init__.py
Normal file
0
nova/tests/ec2/__init__.py
Normal file
540
nova/tests/ec2/test_driver.py
Normal file
540
nova/tests/ec2/test_driver.py
Normal file
@ -0,0 +1,540 @@
|
||||
# Copyright 2016 Platform9 Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from moto import mock_ec2
|
||||
from moto import mock_cloudwatch
|
||||
from moto.ec2 import ec2_backends
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova import test
|
||||
from nova.compute import power_state
|
||||
from nova.compute import vm_states
|
||||
from nova.compute import task_states
|
||||
from nova.image.glance import GlanceImageService
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit import matchers
|
||||
from nova.virt.ec2 import EC2Driver
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
import base64
|
||||
import boto
|
||||
import contextlib
|
||||
import mock
|
||||
|
||||
class EC2DriverTestCase(test.NoDBTestCase):
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudwatch
|
||||
def setUp(self):
|
||||
super(EC2DriverTestCase, self).setUp()
|
||||
self.fake_access_key = 'aws_access_key'
|
||||
self.fake_secret_key = 'aws_secret_key'
|
||||
self.region_name = 'us-east-1'
|
||||
self.region = boto.ec2.get_region(self.region_name)
|
||||
self.flags(access_key=self.fake_access_key,
|
||||
secret_key=self.fake_secret_key,
|
||||
# Region name cannot be fake
|
||||
region_name=self.region_name, group='AWS')
|
||||
self.conn = EC2Driver(None, False)
|
||||
self.type_data = None
|
||||
self.project_id = 'fake'
|
||||
self.user_id = 'fake'
|
||||
self.instance_node = None
|
||||
self.uuid = None
|
||||
self.instance = None
|
||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
self.fake_vpc_conn = boto.vpc.VPCConnection(
|
||||
region=self.region, aws_access_key_id=self.fake_access_key,
|
||||
aws_secret_access_key=self.fake_secret_key)
|
||||
self.fake_ec2_conn = boto.ec2.EC2Connection(
|
||||
aws_access_key_id=self.fake_access_key,
|
||||
aws_secret_access_key=self.fake_secret_key,
|
||||
region=self.region)
|
||||
|
||||
def tearDown(self):
|
||||
super(EC2DriverTestCase, self).tearDown()
|
||||
|
||||
def reset(self):
|
||||
instance_list = self.conn.ec2_conn.get_only_instances()
|
||||
# terminated instances are considered deleted and hence ignore them
|
||||
instance_id_list = [x.id for x in instance_list if x.state != 'terminated']
|
||||
self.conn.ec2_conn.stop_instances(instance_ids=instance_id_list,
|
||||
force=True)
|
||||
self.conn.ec2_conn.terminate_instances(instance_ids=instance_id_list)
|
||||
self.type_data = None
|
||||
self.instance = None
|
||||
self.uuid = None
|
||||
self.instance_node = None
|
||||
|
||||
@mock_ec2
|
||||
def test_list_instances(self):
|
||||
for x in range(0, 5):
|
||||
self.conn.ec2_conn.run_instances('ami-1234abc')
|
||||
fake_list = self.conn.list_instances()
|
||||
self.assertEqual(5, len(fake_list))
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_add_ssh_keys_key_exists(self):
|
||||
fake_key = 'fake_key'
|
||||
fake_key_data = 'abcdefgh'
|
||||
self.conn.ec2_conn.import_key_pair(fake_key, fake_key_data)
|
||||
with contextlib.nested(
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'get_key_pair'),
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'import_key_pair'),
|
||||
) as (fake_get, fake_import):
|
||||
fake_get.return_value = True
|
||||
self.conn._add_ssh_keys(fake_key, fake_key_data)
|
||||
fake_get.assert_called_once_with(fake_key)
|
||||
fake_import.assert_not_called()
|
||||
|
||||
@mock_ec2
|
||||
def test_add_ssh_keys_key_absent(self):
|
||||
fake_key = 'fake_key'
|
||||
fake_key_data = 'abcdefgh'
|
||||
with contextlib.nested(
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'get_key_pair'),
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'import_key_pair'),
|
||||
) as (fake_get, fake_import):
|
||||
fake_get.return_value = False
|
||||
self.conn._add_ssh_keys(fake_key, fake_key_data)
|
||||
fake_get.assert_called_once_with(fake_key)
|
||||
fake_import.assert_called_once_with(fake_key, fake_key_data)
|
||||
|
||||
def test_process_network_info(self):
|
||||
fake_network_info = [
|
||||
{
|
||||
'profile': {},
|
||||
'ovs_interfaceid': None,
|
||||
'preserve_on_delete': False,
|
||||
'network': {
|
||||
'bridge': None,
|
||||
'subnets': [{
|
||||
'ips': [{
|
||||
'meta': {},
|
||||
'version': 4,
|
||||
'type': 'fixed',
|
||||
'floating_ips': [],
|
||||
'address': u'192.168.100.5'}],
|
||||
'version': 4,
|
||||
'meta': {},
|
||||
'dns': [],
|
||||
'routes': [],
|
||||
'cidr': u'192.168.100.0/24',
|
||||
'gateway': {
|
||||
'meta': {},
|
||||
'version': 4,
|
||||
'type': 'gateway',
|
||||
'address': u'192.168.100.1'}}],
|
||||
'meta': {
|
||||
'injected': True,
|
||||
'tenant_id': '135b1a036a51414ea1f989ab59fefde5'},
|
||||
'id': '4f8ad58d-de60-4b52-94ba-8b988a9b7f33',
|
||||
'label': 'test'},
|
||||
'devname': 'tapa9a90cf6-62',
|
||||
'vnic_type': 'normal',
|
||||
'qbh_params': None,
|
||||
'meta': {},
|
||||
'details': '{"subnet_id": "subnet-0107db5a",'
|
||||
' "ip_address": "192.168.100.5"}',
|
||||
'address': 'fa:16:3e:23:65:2c',
|
||||
'active': True,
|
||||
'type': 'vip_type_a',
|
||||
'id': 'a9a90cf6-627c-46f3-829d-c5a2ae07aaf0',
|
||||
'qbg_params': None
|
||||
}
|
||||
]
|
||||
aws_subnet_id, aws_fixed_ip, port_id, network_id = \
|
||||
self.conn._process_network_info(fake_network_info)
|
||||
self.assertEqual(aws_subnet_id, 'subnet-0107db5a')
|
||||
self.assertEqual(aws_fixed_ip, '192.168.100.5')
|
||||
self.assertEqual(port_id, 'a9a90cf6-627c-46f3-829d-c5a2ae07aaf0')
|
||||
self.assertEqual(network_id, '4f8ad58d-de60-4b52-94ba-8b988a9b7f33')
|
||||
|
||||
def _get_instance_flavor_details(self):
|
||||
return {
|
||||
'memory_mb': 2048.0, 'root_gb': 0, 'deleted_at': None,
|
||||
'name': 't2.small', 'deleted': 0, 'created_at': None,
|
||||
'ephemeral_gb': 0, 'updated_at': None, 'disabled': False,
|
||||
'vcpus': 1, 'extra_specs': {}, 'swap': 0, 'rxtx_factor': 1.0,
|
||||
'is_public': True, 'flavorid': '1', 'vcpu_weight': None, 'id': 2
|
||||
}
|
||||
|
||||
def _create_instance(self, key_name=None, key_data=None, user_data=None):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
self.type_data = self._get_instance_flavor_details()
|
||||
values = {
|
||||
'name': 'fake_instance',
|
||||
'id': 1,
|
||||
'uuid': uuid,
|
||||
'project_id': self.project_id,
|
||||
'user_id': self.user_id,
|
||||
'kernel_id': 'fake_kernel_id',
|
||||
'ramdisk_id': 'fake_ramdisk_id',
|
||||
'flavor': objects.flavor.Flavor(**self.type_data),
|
||||
'node': 'fake_node',
|
||||
'memory_mb': self.type_data['memory_mb'],
|
||||
'root_gb': self.type_data['root_gb'],
|
||||
'ephemeral_gb': self.type_data['ephemeral_gb'],
|
||||
'vpcus': self.type_data['vcpus'],
|
||||
'swap': self.type_data['swap'],
|
||||
'expected_attrs': ['system_metadata', 'metadata'],
|
||||
'display_name': 'fake_instance',
|
||||
}
|
||||
if key_name and key_data:
|
||||
values['key_name'] = key_name
|
||||
values['key_data'] = key_data
|
||||
if user_data:
|
||||
values['user_data'] = user_data
|
||||
self.instance_node = 'fake_node'
|
||||
self.uuid = uuid
|
||||
self.instance = fake_instance.fake_instance_obj(self.context, **values)
|
||||
|
||||
def _create_network(self):
|
||||
self.vpc = self.fake_vpc_conn.create_vpc('192.168.100.0/24')
|
||||
self.subnet = self.fake_vpc_conn.create_subnet(self.vpc.id,
|
||||
'192.168.100.0/24')
|
||||
self.subnet_id = self.subnet.id
|
||||
|
||||
def _create_nova_vm(self):
|
||||
self.conn.spawn(self.context, self.instance, None, injected_files=[],
|
||||
admin_password=None, network_info=None,
|
||||
block_device_info=None)
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn(self):
|
||||
self._create_instance()
|
||||
self._create_network()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = (self.subnet_id, '192.168.10.5', None,
|
||||
None)
|
||||
mock_secgrp.return_value = []
|
||||
self._create_nova_vm()
|
||||
fake_instances = self.fake_ec2_conn.get_only_instances()
|
||||
self.assertEqual(len(fake_instances), 1)
|
||||
inst = fake_instances[0]
|
||||
self.assertEqual(inst.vpc_id, self.vpc.id)
|
||||
self.assertEqual(self.subnet_id, inst.subnet_id)
|
||||
self.assertEqual(inst.tags['Name'], 'fake_instance')
|
||||
self.assertEqual(inst.tags['openstack_id'], self.uuid)
|
||||
self.assertEqual(inst.image_id, 'ami-1234abc')
|
||||
self.assertEqual(inst.region.name, self.region_name)
|
||||
self.assertEqual(inst.key_name, 'None')
|
||||
self.assertEqual(inst.instance_type, 't2.small')
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn_with_key(self):
|
||||
self._create_instance(key_name='fake_key', key_data='fake_key_data')
|
||||
self._create_network()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = (self.subnet_id, '192.168.10.5', None,
|
||||
None)
|
||||
mock_secgrp.return_value = []
|
||||
self._create_nova_vm()
|
||||
fake_instances = self.fake_ec2_conn.get_only_instances()
|
||||
self.assertEqual(len(fake_instances), 1)
|
||||
inst = fake_instances[0]
|
||||
self.assertEqual(inst.key_name, 'fake_key')
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn_with_userdata(self):
|
||||
userdata = """
|
||||
#cloud-config
|
||||
password: password
|
||||
"""
|
||||
b64encoded = base64.b64encode(userdata)
|
||||
self._create_instance(user_data=b64encoded)
|
||||
self._create_network()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = (self.subnet_id, '192.168.10.5', None,
|
||||
None)
|
||||
mock_secgrp.return_value = []
|
||||
fake_run_instance_op = self.fake_ec2_conn.run_instances(
|
||||
'ami-1234abc')
|
||||
boto.ec2.EC2Connection.run_instances = mock.Mock()
|
||||
boto.ec2.EC2Connection.run_instances.return_value = \
|
||||
fake_run_instance_op
|
||||
self._create_nova_vm()
|
||||
fake_instances = self.fake_ec2_conn.get_only_instances()
|
||||
self.assertEqual(len(fake_instances), 1)
|
||||
boto.ec2.EC2Connection.run_instances.assert_called_once_with(
|
||||
instance_type='t2.small', key_name=None,
|
||||
image_id='ami-1234abc', user_data=userdata,
|
||||
subnet_id=self.subnet_id,
|
||||
private_ip_address='192.168.10.5',
|
||||
security_group_ids=[])
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn_with_network_error(self):
|
||||
self._create_instance()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = (None, None, None, None)
|
||||
mock_secgrp.return_value = []
|
||||
self.assertRaises(exception.BuildAbortException, self._create_nova_vm)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn_with_network_error_from_aws(self):
|
||||
self._create_instance()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = ('subnet-1234abc', '192.168.10.5',
|
||||
None, None)
|
||||
mock_secgrp.return_value = []
|
||||
self.assertRaises(exception.BuildAbortException, self._create_nova_vm)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_spawn_with_image_error(self):
|
||||
self._create_instance()
|
||||
self._create_network()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.side_effect = exception.BuildAbortException('fake')
|
||||
mock_network.return_value = ('subnet-1234abc', '192.168.10.5',
|
||||
None, None)
|
||||
mock_secgrp.return_value = []
|
||||
self.assertRaises(exception.BuildAbortException, self._create_nova_vm)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def _create_vm_in_aws_nova(self):
|
||||
self._create_instance()
|
||||
self._create_network()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(EC2Driver, '_get_image_ami_id_from_meta'),
|
||||
mock.patch.object(EC2Driver, '_process_network_info'),
|
||||
mock.patch.object(EC2Driver, '_get_instance_sec_grps'),
|
||||
) as (mock_image, mock_network, mock_secgrp):
|
||||
mock_image.return_value = 'ami-1234abc'
|
||||
mock_network.return_value = (self.subnet_id, '192.168.10.5', None,
|
||||
None)
|
||||
mock_secgrp.return_value = []
|
||||
self._create_nova_vm()
|
||||
|
||||
@mock_ec2
|
||||
def test_snapshot(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
GlanceImageService.update = mock.Mock()
|
||||
expected_calls = [
|
||||
{'args': (),
|
||||
'kwargs':
|
||||
{'task_state': task_states.IMAGE_UPLOADING,
|
||||
'expected_state': task_states.IMAGE_SNAPSHOT}}]
|
||||
func_call_matcher = matchers.FunctionCallMatcher(expected_calls)
|
||||
self.conn.snapshot(self.context, self.instance, 'test-snapshot',
|
||||
func_call_matcher.call)
|
||||
self.assertIsNone(func_call_matcher.match())
|
||||
context, snapshot_name, metadata = \
|
||||
GlanceImageService.update.call_args[0]
|
||||
aws_imgs = self.fake_ec2_conn.get_all_images()
|
||||
self.assertEqual(1, len(aws_imgs))
|
||||
aws_img = aws_imgs[0]
|
||||
self.assertEqual(snapshot_name, 'test-snapshot')
|
||||
self.assertEqual(aws_img.name, 'test-snapshot')
|
||||
self.assertEqual(aws_img.id, metadata['properties']['ec2_image_id'])
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_snapshot_instance_not_found(self):
|
||||
boto.ec2.EC2Connection.create_image = mock.Mock()
|
||||
self._create_instance()
|
||||
GlanceImageService.update = mock.Mock()
|
||||
expected_calls = [
|
||||
{'args': (),
|
||||
'kwargs':
|
||||
{'task_state': task_states.IMAGE_UPLOADING,
|
||||
'expected_state': task_states.IMAGE_SNAPSHOT}}]
|
||||
func_call_matcher = matchers.FunctionCallMatcher(expected_calls)
|
||||
self.assertRaises(exception.InstanceNotFound, self.conn.snapshot,
|
||||
self.context, self.instance, 'test-snapshot',
|
||||
func_call_matcher.call)
|
||||
boto.ec2.EC2Connection.create_image.assert_not_called()
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_reboot_soft(self):
|
||||
boto.ec2.EC2Connection.reboot_instances = mock.Mock()
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.conn.reboot(self.context, self.instance, None, 'SOFT', None, None)
|
||||
boto.ec2.EC2Connection.reboot_instances.assert_called_once_with(
|
||||
instance_ids=[fake_inst.id], dry_run=False)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_reboot_hard(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
boto.ec2.EC2Connection.stop_instances = mock.Mock()
|
||||
boto.ec2.EC2Connection.start_instances = mock.Mock()
|
||||
EC2Driver._wait_for_state = mock.Mock()
|
||||
self.conn.reboot(self.context, self.instance, None, 'HARD', None, None)
|
||||
boto.ec2.EC2Connection.stop_instances.assert_called_once_with(
|
||||
instance_ids=[fake_inst.id], force=False, dry_run=False)
|
||||
boto.ec2.EC2Connection.start_instances.assert_called_once_with(
|
||||
instance_ids=[fake_inst.id], dry_run=False)
|
||||
wait_state_calls = EC2Driver._wait_for_state.call_args_list
|
||||
self.assertEqual(2, len(wait_state_calls))
|
||||
self.assertEqual('stopped', wait_state_calls[0][0][2])
|
||||
self.assertEqual(fake_inst.id, wait_state_calls[0][0][1])
|
||||
self.assertEqual('running', wait_state_calls[1][0][2])
|
||||
self.assertEqual(fake_inst.id, wait_state_calls[0][0][1])
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_reboot_instance_not_found(self):
|
||||
self._create_instance()
|
||||
boto.ec2.EC2Connection.stop_instances = mock.Mock()
|
||||
self.assertRaises(exception.InstanceNotFound, self.conn.reboot,
|
||||
self.context, self.instance, None, 'SOFT', None,
|
||||
None)
|
||||
boto.ec2.EC2Connection.stop_instances.assert_not_called()
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_power_off(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.assertEqual(fake_inst.state, 'running')
|
||||
self.conn.power_off(self.instance)
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.assertEqual(fake_inst.state, 'stopped')
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_power_off_instance_not_found(self):
|
||||
self._create_instance()
|
||||
self.assertRaises(exception.InstanceNotFound, self.conn.power_off,
|
||||
self.instance)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_power_on(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.fake_ec2_conn.stop_instances(instance_ids=[fake_inst.id])
|
||||
self.conn.power_on(self.context, self.instance, None, None)
|
||||
fake_inst = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.assertEqual(fake_inst.state, 'running')
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_power_on_instance_not_found(self):
|
||||
self._create_instance()
|
||||
self.assertRaises(exception.InstanceNotFound, self.conn.power_on,
|
||||
self.context, self.instance, None, None)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_destroy(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
self.conn.destroy(self.context, self.instance, None, None)
|
||||
fake_instance = self.fake_ec2_conn.get_only_instances()[0]
|
||||
self.assertEqual('terminated', fake_instance.state)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_destroy_instance_not_found(self):
|
||||
self._create_instance()
|
||||
with contextlib.nested(
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'stop_instances'),
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'terminate_instances'),
|
||||
mock.patch.object(EC2Driver, '_wait_for_state'),
|
||||
) as (fake_stop, fake_terminate, fake_wait):
|
||||
self.conn.destroy(self.context, self.instance, None, None)
|
||||
fake_stop.assert_not_called()
|
||||
fake_terminate.assert_not_called()
|
||||
fake_wait.assert_not_called()
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_destory_instance_terminated_on_aws(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_instances = self.fake_ec2_conn.get_only_instances()
|
||||
self.fake_ec2_conn.stop_instances(instance_ids=[fake_instances[0].id])
|
||||
self.fake_ec2_conn.terminate_instances(
|
||||
instance_ids=[fake_instances[0].id])
|
||||
with contextlib.nested(
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'stop_instances'),
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'terminate_instances'),
|
||||
mock.patch.object(EC2Driver, '_wait_for_state'),
|
||||
) as (fake_stop, fake_terminate, fake_wait):
|
||||
self.conn.destroy(self.context, self.instance, None, None)
|
||||
fake_stop.assert_not_called()
|
||||
fake_terminate.assert_not_called()
|
||||
fake_wait.assert_not_called()
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_destroy_instance_shut_down_on_aws(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
fake_instances = self.fake_ec2_conn.get_only_instances()
|
||||
self.fake_ec2_conn.stop_instances(instance_ids=[fake_instances[0].id])
|
||||
with contextlib.nested(
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'stop_instances'),
|
||||
mock.patch.object(boto.ec2.EC2Connection, 'terminate_instances'),
|
||||
mock.patch.object(EC2Driver, '_wait_for_state'),
|
||||
) as (fake_stop, fake_terminate, fake_wait):
|
||||
self.conn.destroy(self.context, self.instance, None, None)
|
||||
fake_stop.assert_not_called()
|
||||
fake_terminate.assert_called_once_with(instance_ids=[fake_instances[0].id])
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_get_info(self):
|
||||
self._create_vm_in_aws_nova()
|
||||
vm_info = self.conn.get_info(self.instance)
|
||||
self.assertEqual(0, vm_info.state)
|
||||
self.assertEqual(self.instance.id, vm_info.id)
|
||||
self.reset()
|
||||
|
||||
@mock_ec2
|
||||
def test_get_info_instance_not_found(self):
|
||||
self._create_instance()
|
||||
self.assertRaises(exception.InstanceNotFound, self.conn.get_info,
|
||||
self.instance)
|
||||
self.reset()
|
Loading…
Reference in New Issue
Block a user