Second patch for volume support.
[snaps.git] / snaps / openstack / utils / neutron_utils.py
index 061bc56..806bb53 100644 (file)
@@ -20,6 +20,7 @@ from neutronclient.neutron.client import Client
 from snaps.domain.network import (
     Port, SecurityGroup, SecurityGroupRule, Router, InterfaceRouter, Subnet,
     Network)
 from snaps.domain.network import (
     Port, SecurityGroup, SecurityGroupRule, Router, InterfaceRouter, Subnet,
     Network)
+from snaps.domain.project import NetworkQuotas
 from snaps.domain.vm_inst import FloatingIp
 from snaps.openstack.utils import keystone_utils
 
 from snaps.domain.vm_inst import FloatingIp
 from snaps.openstack.utils import keystone_utils
 
@@ -147,19 +148,73 @@ def delete_subnet(neutron, subnet):
         neutron.delete_subnet(subnet.id)
 
 
         neutron.delete_subnet(subnet.id)
 
 
-def get_subnet_by_name(neutron, subnet_name):
+def get_subnet(neutron, subnet_settings=None, subnet_name=None):
     """
     """
-    Returns the first subnet object (dictionary) found with a given name
+    Returns the first subnet object that fits the query else None including
+    if subnet_settings or subnet_name parameters are None.
     :param neutron: the client
     :param neutron: the client
-    :param subnet_name: the name of the network to retrieve
-    :return: a SNAPS-OO Subnet domain object
+    :param subnet_settings: the subnet settings of the object to retrieve
+    :param subnet_name: the name of the subnet to retrieve
+    :return: a SNAPS-OO Subnet domain object or None
     """
     """
-    subnets = neutron.list_subnets(**{'name': subnet_name})
-    for subnet, subnetInst in subnets.items():
-        for inst in subnetInst:
-            if inst['name'] == subnet_name:
-                return Subnet(**inst)
-    return None
+    sub_filter = dict()
+    if subnet_settings:
+        sub_filter['name'] = subnet_settings.name
+        sub_filter['cidr'] = subnet_settings.cidr
+        if subnet_settings.gateway_ip:
+            sub_filter['gateway_ip'] = subnet_settings.gateway_ip
+
+        if subnet_settings.enable_dhcp is not None:
+            sub_filter['enable_dhcp'] = subnet_settings.enable_dhcp
+
+        if subnet_settings.destination:
+            sub_filter['destination'] = subnet_settings.destination
+
+        if subnet_settings.nexthop:
+            sub_filter['nexthop'] = subnet_settings.nexthop
+
+        if subnet_settings.ipv6_ra_mode:
+            sub_filter['ipv6_ra_mode'] = subnet_settings.ipv6_ra_mode
+
+        if subnet_settings.ipv6_address_mode:
+            sub_filter['ipv6_address_mode'] = subnet_settings.ipv6_address_mode
+    elif subnet_name:
+        sub_filter['name'] = subnet_name
+    else:
+        return None
+
+    subnets = neutron.list_subnets(**sub_filter)
+    for subnet in subnets['subnets']:
+        return Subnet(**subnet)
+
+
+def get_subnet_by_id(neutron, subnet_id):
+    """
+    Returns a SNAPS-OO Subnet domain object for a given ID
+    :param neutron: the OpenStack neutron client
+    :param subnet_id: the subnet ID
+    :return: a Subnet object
+    """
+    os_subnet = neutron.show_subnet(subnet_id)
+    if os_subnet and 'subnet' in os_subnet:
+        return Subnet(**os_subnet['subnet'])
+
+
+def get_subnets_by_network(neutron, network):
+    """
+    Returns a list of SNAPS-OO Subnet domain objects
+    :param neutron: the OpenStack neutron client
+    :param network: the SNAPS-OO Network domain object
+    :return: a list of Subnet objects
+    """
+    out = list()
+
+    os_subnets = neutron.list_subnets(network_id=network.id)
+
+    for os_subnet in os_subnets['subnets']:
+        out.append(Subnet(**os_subnet))
+
+    return out
 
 
 def create_router(neutron, os_creds, router_settings):
 
 
 def create_router(neutron, os_creds, router_settings):
@@ -193,18 +248,41 @@ def delete_router(neutron, router):
         neutron.delete_router(router=router.id)
 
 
         neutron.delete_router(router=router.id)
 
 
-def get_router_by_name(neutron, router_name):
+def get_router_by_id(neutron, router_id):
     """
     """
-    Returns the first router object (dictionary) found with a given name
+    Returns a router with a given ID, else None if not found
     :param neutron: the client
     :param neutron: the client
+    :param router_id: the Router ID
+    :return: a SNAPS-OO Router domain object
+    """
+    router = neutron.show_router(router_id)
+    if router:
+        return Router(**router['router'])
+
+
+def get_router(neutron, router_settings=None, router_name=None):
+    """
+    Returns the first router object (dictionary) found the given the settings
+    values if not None, else finds the first with the value of the router_name
+    parameter, else None
+    :param neutron: the client
+    :param router_settings: the RouterSettings object
     :param router_name: the name of the network to retrieve
     :return: a SNAPS-OO Router domain object
     """
     :param router_name: the name of the network to retrieve
     :return: a SNAPS-OO Router domain object
     """
-    routers = neutron.list_routers(**{'name': router_name})
-    for router, routerInst in routers.items():
-        for inst in routerInst:
-            if inst.get('name') == router_name:
-                return Router(**inst)
+    router_filter = dict()
+    if router_settings:
+        router_filter['name'] = router_settings.name
+        if router_settings.admin_state_up is not None:
+            router_filter['admin_state_up'] = router_settings.admin_state_up
+    elif router_name:
+        router_filter['name'] = router_name
+    else:
+        return None
+
+    routers = neutron.list_routers(**router_filter)
+    for routerInst in routers['routers']:
+        return Router(**routerInst)
     return None
 
 
     return None
 
 
@@ -307,21 +385,76 @@ def delete_port(neutron, port):
     neutron.delete_port(port.id)
 
 
     neutron.delete_port(port.id)
 
 
-def get_port_by_name(neutron, port_name):
+def get_port(neutron, port_settings=None, port_name=None):
     """
     """
-    Returns the first port object (dictionary) found with a given name
+    Returns the first port object (dictionary) found for the given query
     :param neutron: the client
     :param neutron: the client
-    :param port_name: the name of the port to retrieve
+    :param port_settings: the PortSettings object used for generating the query
+    :param port_name: if port_settings is None, this name is the value to place
+                      into the query
     :return: a SNAPS-OO Port domain object
     """
     :return: a SNAPS-OO Port domain object
     """
-    ports = neutron.list_ports(**{'name': port_name})
+    port_filter = dict()
+
+    if port_settings:
+        if port_settings.name and len(port_settings.name) > 0:
+            port_filter['name'] = port_settings.name
+        if port_settings.admin_state_up:
+            port_filter['admin_state_up'] = port_settings.admin_state_up
+        if port_settings.device_id:
+            port_filter['device_id'] = port_settings.device_id
+        if port_settings.mac_address:
+            port_filter['mac_address'] = port_settings.mac_address
+        if port_settings.network_name:
+            network = get_network(neutron,
+                                  network_name=port_settings.network_name)
+            port_filter['network_id'] = network.id
+    elif port_name:
+        port_filter['name'] = port_name
+
+    ports = neutron.list_ports(**port_filter)
     for port in ports['ports']:
     for port in ports['ports']:
-        if port['name'] == port_name:
-            return Port(name=port['name'], id=port['id'],
-                        ips=port['fixed_ips'], mac_address=port['mac_address'])
+        return Port(**port)
     return None
 
 
     return None
 
 
+def get_port_by_id(neutron, port_id):
+    """
+    Returns a SNAPS-OO Port domain object for the given ID or none if not found
+    :param neutron: the client
+    :param port_id: the to query
+    :return: a SNAPS-OO Port domain object or None
+    """
+    port = neutron.show_port(port_id)
+    if port:
+        return Port(**port['port'])
+    return None
+
+
+def get_ports(neutron, network, ips=None):
+    """
+    Returns a list of SNAPS-OO Port objects for all OpenStack Port objects that
+    are associated with the 'network' parameter
+    :param neutron: the client
+    :param network: SNAPS-OO Network domain object
+    :param ips: the IPs to lookup if not None
+    :return: a SNAPS-OO Port domain object or None if not found
+    """
+    out = list()
+    ports = neutron.list_ports(**{'network_id': network.id})
+    for port in ports['ports']:
+        if ips:
+            for fixed_ips in port['fixed_ips']:
+                if ('ip_address' in fixed_ips and
+                        fixed_ips['ip_address'] in ips) or ips is None:
+                    out.append(Port(**port))
+                    break
+        else:
+            out.append(Port(**port))
+
+    return out
+
+
 def create_security_group(neutron, keystone, sec_grp_settings):
     """
     Creates a security group object in OpenStack
 def create_security_group(neutron, keystone, sec_grp_settings):
     """
     Creates a security group object in OpenStack
@@ -347,20 +480,38 @@ def delete_security_group(neutron, sec_grp):
     neutron.delete_security_group(sec_grp.id)
 
 
     neutron.delete_security_group(sec_grp.id)
 
 
-def get_security_group(neutron, name):
+def get_security_group(neutron, sec_grp_settings=None, sec_grp_name=None,
+                       project_id=None):
     """
     """
-    Returns the first security group object of the given name else None
+    Returns the first security group for a given query. The query gets built
+    from the sec_grp_settings parameter if not None, else only the name of
+    the security group will be used, else if the query parameters are None then
+    None will be returned
     :param neutron: the client
     :param neutron: the client
-    :param name: the name of security group object to retrieve
+    :param sec_grp_settings: an instance of SecurityGroupSettings config object
+    :param sec_grp_name: the name of security group object to retrieve
+    :param project_id: the ID of the project/tentant object that owns the
+                       secuity group to retrieve
     :return: a SNAPS-OO SecurityGroup domain object or None if not found
     """
     :return: a SNAPS-OO SecurityGroup domain object or None if not found
     """
-    logger.info('Retrieving security group with name - ' + name)
 
 
-    groups = neutron.list_security_groups(**{'name': name})
+    sec_grp_filter = dict()
+    if project_id:
+        sec_grp_filter['tenant_id'] = project_id
+
+    if sec_grp_settings:
+        sec_grp_filter['name'] = sec_grp_settings.name
+
+        if sec_grp_settings.description:
+            sec_grp_filter['description'] = sec_grp_settings.description
+    elif sec_grp_name:
+        sec_grp_filter['name'] = sec_grp_name
+    else:
+        return None
+
+    groups = neutron.list_security_groups(**sec_grp_filter)
     for group in groups['security_groups']:
     for group in groups['security_groups']:
-        if group['name'] == name:
-            return SecurityGroup(**group)
-    return None
+        return SecurityGroup(**group)
 
 
 def get_security_group_by_id(neutron, sec_grp_id):
 
 
 def get_security_group_by_id(neutron, sec_grp_id):
@@ -456,12 +607,13 @@ def get_floating_ips(neutron, ports=None):
     Returns all of the floating IPs
     When ports is not None, FIPs returned must be associated with one of the
     ports in the list and a tuple 2 where the first element being the port's
     Returns all of the floating IPs
     When ports is not None, FIPs returned must be associated with one of the
     ports in the list and a tuple 2 where the first element being the port's
-    name and the second being the FloatingIp SNAPS-OO domain object.
+    ID and the second being the FloatingIp SNAPS-OO domain object.
     When ports is None, all known FloatingIp SNAPS-OO domain objects will be
     returned in a list
     :param neutron: the Neutron client
     When ports is None, all known FloatingIp SNAPS-OO domain objects will be
     returned in a list
     :param neutron: the Neutron client
-    :param ports: a list of SNAPS-OO Port objects to join
-    :return: a list of tuple 2 (port_name, SNAPS FloatingIp) objects when ports
+    :param ports: a list of tuple 2 where index 0 is the port name and index 1
+                  is the SNAPS-OO Port object
+    :return: a list of tuple 2 (port_id, SNAPS FloatingIp) objects when ports
              is not None else a list of Port objects
     """
     out = list()
              is not None else a list of Port objects
     """
     out = list()
@@ -469,13 +621,11 @@ def get_floating_ips(neutron, ports=None):
     for fip in fips['floatingips']:
         if ports:
             for port_name, port in ports:
     for fip in fips['floatingips']:
         if ports:
             for port_name, port in ports:
-                if fip['port_id'] == port.id:
-                    out.append((port.name, FloatingIp(
-                        inst_id=fip['id'], ip=fip['floating_ip_address'])))
+                if port and port.id == fip['port_id']:
+                    out.append((port.id, FloatingIp(**fip)))
                     break
         else:
                     break
         else:
-            out.append(FloatingIp(inst_id=fip['id'],
-                                  ip=fip['floating_ip_address']))
+            out.append(FloatingIp(**fip))
 
     return out
 
 
     return out
 
@@ -495,7 +645,7 @@ def create_floating_ip(neutron, ext_net_name):
             body={'floatingip':
                   {'floating_network_id': ext_net.id}})
 
             body={'floatingip':
                   {'floating_network_id': ext_net.id}})
 
-        return FloatingIp(inst_id=fip['floatingip']['id'],
+        return FloatingIp(id=fip['floatingip']['id'],
                           ip=fip['floatingip']['floating_ip_address'])
     else:
         raise NeutronException(
                           ip=fip['floatingip']['floating_ip_address'])
     else:
         raise NeutronException(
@@ -514,8 +664,7 @@ def get_floating_ip(neutron, floating_ip):
                  floating_ip.ip)
     os_fip = __get_os_floating_ip(neutron, floating_ip)
     if os_fip:
                  floating_ip.ip)
     os_fip = __get_os_floating_ip(neutron, floating_ip)
     if os_fip:
-        return FloatingIp(
-            inst_id=os_fip['id'], ip=os_fip['floating_ip_address'])
+        return FloatingIp(id=os_fip['id'], ip=os_fip['floating_ip_address'])
 
 
 def __get_os_floating_ip(neutron, floating_ip):
 
 
 def __get_os_floating_ip(neutron, floating_ip):
@@ -547,6 +696,39 @@ def delete_floating_ip(neutron, floating_ip):
     return neutron.delete_floatingip(floating_ip.id)
 
 
     return neutron.delete_floatingip(floating_ip.id)
 
 
+def get_network_quotas(neutron, project_id):
+    """
+    Returns a list of all available keypairs
+    :param neutron: the neutron client
+    :param project_id: the project's ID of the quotas to lookup
+    :return: an object of type NetworkQuotas or None if not found
+    """
+    quota = neutron.show_quota(project_id)
+    if quota:
+        return NetworkQuotas(**quota['quota'])
+
+
+def update_quotas(neutron, project_id, network_quotas):
+    """
+    Updates the networking quotas for a given project
+    :param neutron: the Neutron client
+    :param project_id: the project's ID that requires quota updates
+    :param network_quotas: an object of type NetworkQuotas containing the
+                           values to update
+    :return:
+    """
+    update_body = dict()
+    update_body['security_group'] = network_quotas.security_group
+    update_body['security_group_rule'] = network_quotas.security_group_rule
+    update_body['floatingip'] = network_quotas.floatingip
+    update_body['network'] = network_quotas.network
+    update_body['port'] = network_quotas.port
+    update_body['router'] = network_quotas.router
+    update_body['subnet'] = network_quotas.subnet
+
+    return neutron.update_quota(project_id, {'quota': update_body})
+
+
 class NeutronException(Exception):
     """
     Exception when calls to the Keystone client cannot be served properly
 class NeutronException(Exception):
     """
     Exception when calls to the Keystone client cannot be served properly