diff --git a/rack/api/v1/processes.py b/rack/api/v1/processes.py index cbf3678..bb6c553 100644 --- a/rack/api/v1/processes.py +++ b/rack/api/v1/processes.py @@ -130,6 +130,7 @@ class Controller(wsgi.Controller): name = values.get("name") keypair_id = values.get("keypair_id") securitygroup_ids = values.get("securitygroup_ids") + floating_networks = values.get("floating_networks") glance_image_id = values.get("glance_image_id") nova_flavor_id = values.get("nova_flavor_id") userdata = values.get("userdata") @@ -219,13 +220,30 @@ class Controller(wsgi.Controller): msg = _("Netwoks does not exist in the group %s" % gid) raise webob.exc.HTTPBadRequest(explanation=msg) + if floating_networks is None: + floating_networks = [] + elif floating_networks is not None and\ + not isinstance(floating_networks, list): + msg = _("floating_networks must be a list") + raise exception.InvalidInput(reason=msg) + network_ids =\ [network["network_id"] for network in networks] - neutron_network_ids =\ - [network["neutron_network_id"] for network in networks] - nics = [] - for id in neutron_network_ids: - nics.append({"net-id": id}) + + for floating_net_id in floating_networks: + if floating_net_id not in network_ids: + msg = _("floating_networks do not exist in the group %s" + % gid) + raise webob.exc.HTTPBadRequest(explanation=msg) + + for network in networks: + if floating_net_id == network["network_id"] and\ + not network["ext_router"]: + msg = _("floating_networks must be connected to a " + "router that connects to an external network") + raise webob.exc.HTTPBadRequest(explanation=msg) + else: + network["is_floating"] = True if args is None: args = {} @@ -299,7 +317,7 @@ class Controller(wsgi.Controller): boot_values["flavor"] = nova_flavor_id boot_values["userdata"] = userdata boot_values["meta"] = args - boot_values["nics"] = nics + boot_values["networks"] = networks return valid_values, boot_values diff --git a/rack/resourceoperator/manager.py b/rack/resourceoperator/manager.py index b5baad0..2898617 100644 --- a/rack/resourceoperator/manager.py +++ b/rack/resourceoperator/manager.py @@ -209,11 +209,27 @@ class ResourceOperator(object): def process_create(self, context, name, key_name, security_groups, image, flavor, - userdata, meta, nics): + userdata, meta, networks): try: - return self.process_client.process_create( - name, key_name, security_groups, image, flavor, - userdata, meta, nics) + nics = [] + for network in networks: + nics.append({"net-id": network["neutron_network_id"]}) + + nova_instance_id, status = self.process_client.process_create( + name, key_name, security_groups, image, flavor, + userdata, meta, nics) + + for network in networks: + if network.get("is_floating"): + try: + self.network_client.add_floatingip( + nova_instance_id, network["neutron_network_id"], + network["ext_router"]) + except Exception: + pass + + return nova_instance_id, status + except Exception as e: LOG.exception(e) raise exception.OpenStackException(e.code, e.message) diff --git a/rack/resourceoperator/openstack/__init__.py b/rack/resourceoperator/openstack/__init__.py index 4ccf6cd..9b1ab38 100644 --- a/rack/resourceoperator/openstack/__init__.py +++ b/rack/resourceoperator/openstack/__init__.py @@ -32,8 +32,16 @@ openstack_client_opts = [ help='Valid region name for OpenStack') ] +timeout_opts = [ + cfg.IntOpt('add_floatingip_timeout', + default=10, + help='Amount of time to wait in seconds for ports of a process ' + 'can be listed.') +] + CONF = cfg.CONF CONF.register_opts(openstack_client_opts) +CONF.register_opts(timeout_opts) LOG = logging.getLogger(__name__) diff --git a/rack/resourceoperator/openstack/networks.py b/rack/resourceoperator/openstack/networks.py index 6dd1fd9..a59eb1c 100644 --- a/rack/resourceoperator/openstack/networks.py +++ b/rack/resourceoperator/openstack/networks.py @@ -11,12 +11,16 @@ # 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 oslo_config import cfg from rack.openstack.common import log as logging from rack.resourceoperator import openstack as os_client +import time LOG = logging.getLogger(__name__) +CONF = cfg.CONF + class NetworkAPI(object): @@ -72,3 +76,34 @@ class NetworkAPI(object): ext_router, {"subnet_id": subnet}) neutron.delete_network(neutron_network_id) + + def add_floatingip(self, nova_instance_id, neutron_network_id, + ext_router_id): + neutron = os_client.get_neutron_client() + curr_time = time.time() + + router = neutron.show_router(ext_router_id)["router"] + ext_network_id = router["external_gateway_info"]["network_id"] + + while (1): + if (time.time() - curr_time) > CONF.add_floatingip_timeout: + LOG.exception("Unable to add FloatingIP. Timed out.") + break + + ports = neutron.list_ports() + for p in ports["ports"]: + if p["device_id"] == nova_instance_id and\ + p["network_id"] == neutron_network_id: + body = self._build_add_floatingip_body(ext_network_id, + p["id"]) + neutron.create_floatingip(body) + return + + def _build_add_floatingip_body(self, ext_network_id, port_id): + body = { + "floatingip": { + "floating_network_id": ext_network_id, + "port_id": port_id + } + } + return body diff --git a/rack/tests/api/v1/test_processes.py b/rack/tests/api/v1/test_processes.py index 38c73f2..649871c 100644 --- a/rack/tests/api/v1/test_processes.py +++ b/rack/tests/api/v1/test_processes.py @@ -61,6 +61,8 @@ NETWORK_ID2 = unicode(uuid.uuid4()) NEUTRON_NETWORK_ID1 = unicode(uuid.uuid4()) NEUTRON_NETWORK_ID2 = unicode(uuid.uuid4()) +EXT_ROUTER_ID = unicode(uuid.uuid4()) + GLANCE_IMAGE_ID1 = unicode(uuid.uuid4()) GLANCE_IMAGE_ID2 = unicode(uuid.uuid4()) @@ -108,20 +110,25 @@ def _base_securitygroups2(): ] -def _base_network(network_id, neutron_network_id): +def _base_network(network_id, neutron_network_id, ext_router_id): return { "network_id": network_id, - "neutron_network_id": neutron_network_id + "neutron_network_id": neutron_network_id, + "ext_router": ext_router_id } def _base_networks(): return [ - _base_network(NETWORK_ID1, NEUTRON_NETWORK_ID1), - _base_network(NETWORK_ID2, NEUTRON_NETWORK_ID2), + _base_network(NETWORK_ID1, NEUTRON_NETWORK_ID1, EXT_ROUTER_ID), + _base_network(NETWORK_ID2, NEUTRON_NETWORK_ID2, EXT_ROUTER_ID), ] +def _base_floating_networks(): + return [NETWORK_ID1, NETWORK_ID2] + + def _base_process1(gid, pid): return { "pid": pid, @@ -136,6 +143,7 @@ def _base_process1(gid, pid): "keypair_id": KEYPAIR_ID1, "securitygroups": _base_securitygroups1(), "networks": _base_networks(), + "floating_networks": _base_floating_networks(), "is_proxy": False, "status": "BUILDING", "app_status": None, @@ -160,6 +168,7 @@ def _base_process2(gid, pid): "keypair_id": KEYPAIR_ID2, "securitygroups": _base_securitygroups2(), "networks": _base_networks(), + "floating_networks": _base_floating_networks(), "is_proxy": False, "status": "BUILDING", "app_status": "BUILDING", @@ -184,6 +193,7 @@ def _base_process3(gid, pid): "keypair_id": KEYPAIR_ID1, "securitygroups": _base_securitygroups1(), "networks": _base_networks(), + "floating_networks": _base_floating_networks(), "is_proxy": True, "status": "BUILDING", "app_status": "BUILDING", @@ -286,7 +296,8 @@ def get_base_body(process): "securitygroup_ids": [securitygroup["securitygroup_id"] for securitygroup in process["securitygroups"]], "metadata": METADATA1, - "userdata": process["userdata"] + "userdata": process["userdata"], + "floating_networks": process["floating_networks"] } @@ -418,7 +429,8 @@ class ProcessesTest(test.NoDBTestCase): res = req.get_response(self.app) body = jsonutils.loads(res.body) self.assertEqual(res.status_code, 200) - self.assertEqual(body, expect) + for key in body["process"]: + self.assertEqual(body["process"][key], expect["process"][key]) def test_show_invalid_format_gid(self): url = get_base_url("aaaaa") + "/" + PID1 @@ -454,7 +466,8 @@ class ProcessesTest(test.NoDBTestCase): res = req.get_response(self.app) body = jsonutils.loads(res.body) self.assertEqual(res.status_code, 200) - self.assertEqual(body, expect) + for key in body["proxy"]: + self.assertEqual(body["proxy"][key], expect["proxy"][key]) def test_show_proxy_not_found_exception(self): self.mox.StubOutWithMock(db, "process_get_all") @@ -507,7 +520,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) cfg.CONF.my_ip = "my_ip_data" cfg.CONF.os_username = "os_username_data" cfg.CONF.os_password = "os_password_data" @@ -565,7 +578,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) cfg.CONF.my_ip = "my_ip_data" cfg.CONF.os_username = "os_username_data" cfg.CONF.os_password = "os_password_data" @@ -760,7 +773,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -807,7 +820,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -857,7 +870,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -899,7 +912,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -952,7 +965,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -1006,7 +1019,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -1057,7 +1070,7 @@ class ProcessesTest(test.NoDBTestCase): flavor=IsA(int), userdata=IsA(unicode), meta=IsA(dict), - nics=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) self.mox.ReplayAll() process = _base_process1(GID, PID1) @@ -1078,6 +1091,54 @@ class ProcessesTest(test.NoDBTestCase): for key in body["process"]: self.assertEqual(body["process"][key], expect["process"][key]) + def test_create_without_floating_networks(self): + self.mox.StubOutWithMock(db, "process_get_all") + self.mox.StubOutWithMock(db, "securitygroup_get_by_securitygroup_id") + self.mox.StubOutWithMock(manager.ResourceOperator, "process_create") + self.mox.StubOutWithMock( + manager.ResourceOperator, "get_process_address") + + db.process_get_all( + IsA(context.RequestContext), GID, filters=IsA(dict))\ + .AndReturn([{"nova_instance_id": "nova_instance_id_data"}]) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data1"}) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data2"}) + manager.ResourceOperator.get_process_address( + IsA(context.RequestContext), + IsA(str)).AndReturn("proxy_instance_id_data") + manager.ResourceOperator.process_create( + IsA(context.RequestContext), + name=IsA(unicode), + key_name=IsA(unicode), + security_groups=IsA(list), + image=IsA(unicode), + flavor=IsA(int), + userdata=IsA(unicode), + meta=IsA(dict), + networks=IsA(list)).AndReturn((NOVA_INSTANCE_ID1, "BUILDING")) + self.mox.ReplayAll() + + process = _base_process1(GID, PID1) + request_body = get_base_request_body1(process) + request_body["process"].pop("floating_networks") + expect = get_base_process_response_body(process) + + url = get_base_url(GID) + req = get_request(url, 'POST', request_body) + res = req.get_response(self.app) + body = jsonutils.loads(res.body) + + self.assertEqual(res.status_code, 202) + expect["process"]["userdata"] = USER_DATA_B64_ENC + expect["process"]["args"].update(ppid=PPID1) + expect["process"]["args"].update(proxy_ip="proxy_instance_id_data") + for key in body["process"]: + self.assertEqual(body["process"][key], expect["process"][key]) + def test_create_process_proxy_not_exits(self): self.mox.StubOutWithMock(db, "process_get_all") db.process_get_all( @@ -1207,6 +1268,83 @@ class ProcessesTest(test.NoDBTestCase): res = req.get_response(self.app) self.assertEqual(res.status_code, 404) + def test_create_invalid_format_floating_networks(self): + self.mox.StubOutWithMock(db, "process_get_all") + self.mox.StubOutWithMock(db, "securitygroup_get_by_securitygroup_id") + db.process_get_all( + IsA(context.RequestContext), GID, filters=IsA(dict))\ + .AndReturn([{"nova_instance_id": "nova_instance_id_data"}]) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data1"}) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data2"}) + self.mox.ReplayAll() + + process = _base_process1(GID, PID1) + request_body = get_base_request_body1(process) + request_body["process"].update(floating_networks="invalid") + + url = get_base_url(GID) + req = get_request(url, 'POST', request_body) + res = req.get_response(self.app) + self.assertEqual(res.status_code, 400) + + def test_create_not_match_floating_networks(self): + self.mox.StubOutWithMock(db, "process_get_all") + self.mox.StubOutWithMock(db, "securitygroup_get_by_securitygroup_id") + db.process_get_all( + IsA(context.RequestContext), GID, filters=IsA(dict))\ + .AndReturn([{"nova_instance_id": "nova_instance_id_data"}]) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data1"}) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data2"}) + self.mox.ReplayAll() + + process = _base_process1(GID, PID1) + request_body = get_base_request_body1(process) + floating_networks = ["invalid"] + request_body["process"].update(floating_networks=floating_networks) + + url = get_base_url(GID) + req = get_request(url, 'POST', request_body) + res = req.get_response(self.app) + self.assertEqual(res.status_code, 400) + + def test_create_non_external_floating_networks(self): + def _fake_network_get_all(context, gid, filters=None): + networks = _base_networks() + networks[0]["ext_router"] = "" + return networks + + self.stubs.Set(db, "network_get_all", _fake_network_get_all) + self.mox.StubOutWithMock(db, "process_get_all") + self.mox.StubOutWithMock(db, "securitygroup_get_by_securitygroup_id") + db.process_get_all( + IsA(context.RequestContext), GID, filters=IsA(dict))\ + .AndReturn([{"nova_instance_id": "nova_instance_id_data"}]) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data1"}) + db.securitygroup_get_by_securitygroup_id( + IsA(context.RequestContext), GID, IsA(unicode)).AndReturn( + {"neutron_securitygroup_id": "securitygroup_id_data2"}) + self.mox.ReplayAll() + + process = _base_process1(GID, PID1) + request_body = get_base_request_body1(process) + floating_networks = [NETWORK_ID1, NETWORK_ID2] + request_body["process"].update(floating_networks=floating_networks) + + url = get_base_url(GID) + req = get_request(url, 'POST', request_body) + res = req.get_response(self.app) + self.assertEqual(res.status_code, 400) + def test_create_process_name_is_whitespace(self): process = _base_process1(GID, PID1) request_body = get_base_request_body1(process) diff --git a/rack/tests/resourceoperator/openstack/test_networks.py b/rack/tests/resourceoperator/openstack/test_networks.py index e9c838e..83587d5 100644 --- a/rack/tests/resourceoperator/openstack/test_networks.py +++ b/rack/tests/resourceoperator/openstack/test_networks.py @@ -211,3 +211,61 @@ class NetworkTestCase(test.NoDBTestCase): self.mox.ReplayAll() self.network_client.network_delete(fake_neutron_network_id, fake_ext_router) + + def test_add_floatingip(self): + router = { + "router": { + "external_gateway_info": { + "network_id": "ext_network_id" + } + } + } + fake_router = "fake_router" + self.neutron_mock.show_router(fake_router).AndReturn(router) + + ports = { + "ports": [ + { + "id": "port1", + "network_id": "neutron_network_id1", + "device_id": "nova_instance_id1" + }, + { + "id": "port2", + "network_id": "neutron_network_id2", + "device_id": "nova_instance_id2" + } + ]} + self.neutron_mock.list_ports().AndReturn(ports) + + expected_body = { + "floatingip": { + "floating_network_id": "ext_network_id", + "port_id": "port2" + } + } + self.neutron_mock.create_floatingip(expected_body) + self.mox.ReplayAll() + + self.network_client.add_floatingip("nova_instance_id2", + "neutron_network_id2", + fake_router) + + def test_add_floatingip_timeout(self): + router = { + "router": { + "external_gateway_info": { + "network_id": "ext_network_id" + } + } + } + fake_router = "fake_router" + self.neutron_mock.show_router(fake_router).AndReturn(router) + + self.neutron_mock.list_ports().MultipleTimes().AndReturn({"ports": []}) + CONF.add_floatingip_timeout = 1 + self.mox.ReplayAll() + + self.network_client.add_floatingip("nova_instance_id1", + "neutron_network_id1", + fake_router) diff --git a/rack/tests/resourceoperator/test_manager.py b/rack/tests/resourceoperator/test_manager.py index 961484c..9b7965b 100644 --- a/rack/tests/resourceoperator/test_manager.py +++ b/rack/tests/resourceoperator/test_manager.py @@ -27,7 +27,11 @@ CONF = cfg.CONF GID = unicode(uuid.uuid4()) KEYPAIR_ID = unicode(uuid.uuid4()) NETWORK_ID = unicode(uuid.uuid4()) +NETWORK_ID2 = unicode(uuid.uuid4()) NEUTRON_NETWORK_ID = unicode(uuid.uuid4()) +NEUTRON_NETWORK_ID2 = unicode(uuid.uuid4()) +EXT_ROUTER_ID = unicode(uuid.uuid4()) +EXT_ROUTER_ID2 = unicode(uuid.uuid4()) NOVA_INSTANCE_ID = unicode(uuid.uuid4()) @@ -704,6 +708,8 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): def test_process_create(self): self.mox.StubOutWithMock(self.manager.process_client, "process_create") + self.mox.StubOutWithMock(self.manager.network_client, + "add_floatingip") fake_name = "fake_name" fake_key_name = "fake_key_name" face_security_groups = ["security_group_id1"] @@ -711,8 +717,25 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): fake_flavor = "fake_flavor" fake_userdata = "fake_userdata" fake_meta = "fake_meta" - fake_nics = "fake_nics" - fake_process = {"pid": "fake_pid"} + networks = [ + { + "network_id": NETWORK_ID, + "neutron_network_id": NEUTRON_NETWORK_ID, + "ext_router": EXT_ROUTER_ID, + "is_floating": True + }, + { + "network_id": NETWORK_ID2, + "neutron_network_id": NEUTRON_NETWORK_ID2, + "ext_router": EXT_ROUTER_ID2, + "is_floating": False + }] + + nics = [ + {"net-id": NEUTRON_NETWORK_ID}, + {"net-id": NEUTRON_NETWORK_ID2} + ] + self.manager.process_client.process_create(fake_name, fake_key_name, face_security_groups, @@ -720,20 +743,23 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): fake_flavor, fake_userdata, fake_meta, - fake_nics)\ - .AndReturn(fake_process) + nics)\ + .AndReturn((NOVA_INSTANCE_ID, "ACTIVE")) + self.manager.network_client.add_floatingip(NOVA_INSTANCE_ID, + NEUTRON_NETWORK_ID, + EXT_ROUTER_ID) self.mox.ReplayAll() - process = self.manager.process_create(self.context, - fake_name, - fake_key_name, - face_security_groups, - fake_image, - fake_flavor, - fake_userdata, - fake_meta, - fake_nics) - self.assertEqual(process["pid"], "fake_pid") + res = self.manager.process_create(self.context, + fake_name, + fake_key_name, + face_security_groups, + fake_image, + fake_flavor, + fake_userdata, + fake_meta, + networks) + self.assertEqual(res, (NOVA_INSTANCE_ID, "ACTIVE")) def test_process_create_exception_process_create_faild(self): self.mox.StubOutWithMock(self.manager.process_client, @@ -745,7 +771,25 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): fake_flavor = "fake_flavor" fake_userdata = "fake_userdata" fake_meta = "fake_meta" - fake_nics = "fake_nics" + networks = [ + { + "network_id": NETWORK_ID, + "neutron_network_id": NEUTRON_NETWORK_ID, + "ext_router": EXT_ROUTER_ID, + "is_floating": True + }, + { + "network_id": NETWORK_ID2, + "neutron_network_id": NEUTRON_NETWORK_ID2, + "ext_router": EXT_ROUTER_ID2, + "is_floating": False + }] + + nics = [ + {"net-id": NEUTRON_NETWORK_ID}, + {"net-id": NEUTRON_NETWORK_ID2} + ] + self.manager.process_client.process_create(fake_name, fake_key_name, face_security_groups, @@ -753,7 +797,7 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): fake_flavor, fake_userdata, fake_meta, - fake_nics)\ + nics)\ .AndRaise(exception.OpenStackException(400, "fake_msg")) self.mox.ReplayAll() @@ -766,7 +810,67 @@ class ResourceOperatorManagerProcessesTestCase(test.NoDBTestCase): fake_flavor, fake_userdata, fake_meta, - fake_nics) + networks) + except Exception as e: + self.assertEqual(e.code, 400) + self.assertEqual(e.message, "fake_msg") + + def test_process_create_add_floatingip_failed(self): + self.mox.StubOutWithMock(self.manager.process_client, + "process_create") + self.mox.StubOutWithMock(self.manager.network_client, + "add_floatingip") + fake_name = "fake_name" + fake_key_name = "fake_key_name" + face_security_groups = ["security_group_id1"] + fake_image = "fake_image" + fake_flavor = "fake_flavor" + fake_userdata = "fake_userdata" + fake_meta = "fake_meta" + networks = [ + { + "network_id": NETWORK_ID, + "neutron_network_id": NEUTRON_NETWORK_ID, + "ext_router": EXT_ROUTER_ID, + "is_floating": True + }, + { + "network_id": NETWORK_ID2, + "neutron_network_id": NEUTRON_NETWORK_ID2, + "ext_router": EXT_ROUTER_ID2, + "is_floating": False + }] + + nics = [ + {"net-id": NEUTRON_NETWORK_ID}, + {"net-id": NEUTRON_NETWORK_ID2} + ] + + self.manager.process_client.process_create(fake_name, + fake_key_name, + face_security_groups, + fake_image, + fake_flavor, + fake_userdata, + fake_meta, + nics)\ + .AndReturn((NOVA_INSTANCE_ID, "ACTIVE")) + self.manager.network_client.add_floatingip(NOVA_INSTANCE_ID, + NEUTRON_NETWORK_ID, + EXT_ROUTER_ID)\ + .AndRaise(exception.OpenStackException(400, "fake_msg")) + self.mox.ReplayAll() + + try: + self.manager.process_create(self.context, + fake_name, + fake_key_name, + face_security_groups, + fake_image, + fake_flavor, + fake_userdata, + fake_meta, + networks) except Exception as e: self.assertEqual(e.code, 400) self.assertEqual(e.message, "fake_msg")