diff --git a/cloudcafe/compute/servers_api/client.py b/cloudcafe/compute/servers_api/client.py index d74145e2..9d5b8d44 100644 --- a/cloudcafe/compute/servers_api/client.py +++ b/cloudcafe/compute/servers_api/client.py @@ -33,6 +33,10 @@ from cloudcafe.compute.servers_api.models.requests import ChangePassword, \ ConfirmResize, RevertResize, Resize, Reboot, MigrateServer, Lock, \ Unlock, Start, Stop, Suspend, Resume, Pause, Unpause, CreateImage, \ Rebuild, ResetState, CreateBackup, LiveMigrateServer, Evacuate +from cloudcafe.networking.networks.common.models.request.\ + virtual_interface import VirtualInterface as RequestVirtualInterface +from cloudcafe.networking.networks.common.models.response.\ + virtual_interface import VirtualInterface as ResponseVirtualInterface class ServersClient(AutoMarshallingHTTPClient): @@ -902,3 +906,20 @@ class ServersClient(AutoMarshallingHTTPClient): response_entity_type=Password, requestslib_kwargs=requestslib_kwargs) return resp + + def create_virtual_interface(self, server_id, network_id, + requestslib_kwargs=None): + virtual_interface = RequestVirtualInterface(network_id=network_id) + url = '{base_url}/servers/{server_id}/os-virtual-interfacesv2'.format( + base_url=self.url, server_id=server_id) + return self.request('POST', url, + response_entity_type=ResponseVirtualInterface, + request_entity=virtual_interface, + requestslib_kwargs=requestslib_kwargs) + + def list_virtual_interfaces(self, server_id, requestslib_kwargs=None): + url = '{base_url}/servers/{server_id}/os-virtual-interfacesv2'.format( + base_url=self.url, server_id=server_id) + return self.request('GET', url, + response_entity_type=ResponseVirtualInterface, + requestslib_kwargs=requestslib_kwargs) diff --git a/cloudcafe/networking/networks/common/constants.py b/cloudcafe/networking/networks/common/constants.py index a7a4cff1..a5adefd8 100644 --- a/cloudcafe/networking/networks/common/constants.py +++ b/cloudcafe/networking/networks/common/constants.py @@ -72,6 +72,10 @@ class NeutronResponseCodes(object): ADD_FIXED_IP = 202 REMOVE_FIXED_IP = 202 + CREATE_INTERFACE = 200 + LIST_INTERFACES = 200 + DELETE_INTERFACE = 200 + BAD_REQUEST = 400 UNAUTHORIZED = 401 FORBIDDEN = 403 diff --git a/cloudcafe/networking/networks/common/models/request/virtual_interface.py b/cloudcafe/networking/networks/common/models/request/virtual_interface.py new file mode 100644 index 00000000..d0cca94a --- /dev/null +++ b/cloudcafe/networking/networks/common/models/request/virtual_interface.py @@ -0,0 +1,33 @@ +""" +Copyright 2018 Rackspace + +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 json + +from cafe.engine.models.base import AutoMarshallingModel + + +class VirtualInterface(AutoMarshallingModel): + ROOT_TAG = 'virtual_interface' + + def __init__(self, network_id=None): + """ + An object that represents the data of a Virtual Interface + """ + super(VirtualInterface, self).__init__() + self.network_id = network_id + + def _obj_to_json(self): + ret = {self.ROOT_TAG: {'network_id': self.network_id}} + return json.dumps(ret) diff --git a/cloudcafe/networking/networks/common/models/response/virtual_interface.py b/cloudcafe/networking/networks/common/models/response/virtual_interface.py new file mode 100644 index 00000000..84d017ad --- /dev/null +++ b/cloudcafe/networking/networks/common/models/response/virtual_interface.py @@ -0,0 +1,100 @@ +""" +Copyright 2018 Rackspace + +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 json + +from cafe.engine.models.base import AutoMarshallingModel + + +class VirtualInterface(AutoMarshallingModel): + + def __init__(self, id_=None, mac_address=None, ip_addresses=None): + + """ + An object that represents the data of a Virtual Interface. + """ + super(VirtualInterface, self).__init__() + self.id = id_ + self.mac_address = mac_address + self.ip_addresses = ip_addresses or [] + + def get_ipv4_address(self, network_id): + ret = None + for ip_address in self.ip_addresses: + if (ip_address.network_id == network_id and + ip_address.address.find('.') > 0): + ret = ip_address + break + return ret + + def get_ipv6_address(self, network_id): + ret = None + for ip_address in self.ip_addresses: + if (ip_address.network_id == network_id and + ip_address.address.find(':') > 0): + ret = ip_address + break + return ret + + @property + def network_label(self): + for ip_address in self.ip_addresses: + if ip_address.network_label is not None: + return ip_address.network_label + + @property + def network_id(self): + for ip_address in self.ip_addresses: + if ip_address.network_id is not None: + return ip_address.network_id + + @classmethod + def _json_to_obj(cls, serialized_str): + ret = None + vif = 'virtual_interface' + json_dict = json.loads(serialized_str) + if vif in json_dict: + interface_dict = json_dict.get(vif) + ip_addrs = IPAddress._dict_to_obj(interface_dict) + interface_dict['ip_addresses'] = ip_addrs + ret = VirtualInterface(**interface_dict) + if vif in json_dict: + ret = [] + for interface_dict in json_dict.get(vif): + ip_addrs = IPAddress._dict_to_obj(interface_dict) + interface_dict['ip_addresses'] = ip_addrs + ret.append(VirtualInterface(**interface_dict)) + return ret + + +class IPAddress(AutoMarshallingModel): + + def __init__(self, network_id=None, network_label=None, address=None): + super(IPAddress, self).__init__() + self.network_id = network_id + self.network_label = network_label + self.address = address + + @classmethod + def _json_to_obj(cls, serialized_str): + json_dict = json.loads(serialized_str) + return cls._dict_to_obj(json_dict) + + @classmethod + def _dict_to_obj(cls, json_dict): + ret = [] + if 'ip_addresses' in json_dict: + ret = [IPAddress(**addr) for addr in json_dict.get('ip_addresses')] + return ret