Beispiel #1
0
class ExternalNetworkStackFixture(heat.HeatStackFixture):

    template = _hot.heat_template_file('neutron/external_network.yaml')

    @property
    def external_name(self):
        return tobiko.tobiko_config().neutron.external_network

    subnet_enable_dhcp: typing.Optional[bool] = False

    _external_network: typing.Optional[NeutronNetworkType] = None

    @property
    def external_network(self) -> typing.Optional[NeutronNetworkType]:
        external_network = self._external_network
        if external_network is None:
            subnet_parameters = {}
            if self.subnet_enable_dhcp is not None:
                subnet_parameters['enable_dhcp'] = self.subnet_enable_dhcp
            for network in list_external_networks(name=self.external_name):
                if not network['subnets']:
                    LOG.debug(f"Network '{network['id']}' has any subnet")
                    continue
                subnets = neutron.list_subnets(network_id=network['id'],
                                               **subnet_parameters)
                if not subnets:
                    LOG.debug(f"Network '{network['id']}' has any valid "
                              f"subnet: {subnet_parameters}")
                    continue

                network_dump = json.dumps(network, indent=4, sort_keys=True)
                LOG.debug(f"Found external network for {self.fixture_name}:\n"
                          f"{network_dump}")

                subnets_dump = json.dumps(subnets, indent=4, sort_keys=True)
                LOG.debug(f"External subnets for {self.fixture_name}:\n"
                          f"{subnets_dump}")
                self._external_network = external_network = network
                break
            else:
                LOG.warning("No external network found for "
                            f"'{self.fixture_name}':\n"
                            f" - name or ID: {self.external_name}\n"
                            f" - subnet attributes: {subnet_parameters}\n")
        return external_network

    @property
    def external_id(self):
        network = self.external_network
        return network and network['id'] or None

    @property
    def has_external_id(self):
        return bool(self.external_id)

    @property
    def network_details(self):
        return neutron.get_network(self.network_id)

    has_gateway = False
Beispiel #2
0
class KeyPairStackFixture(heat.HeatStackFixture):
    template = _hot.heat_template_file('nova/key_pair.yaml')
    key_file = os.path.expanduser(CONF.tobiko.nova.key_file)
    public_key = None
    private_key = None

    def setup_fixture(self):
        self.create_key_file()
        self.read_keys()
        super(KeyPairStackFixture, self).setup_fixture()

    def read_keys(self):
        with open(self.key_file, 'r') as fd:
            self.private_key = as_str(fd.read())
        with open(self.key_file + '.pub', 'r') as fd:
            self.public_key = as_str(fd.read())

    def create_key_file(self):
        key_file = os.path.realpath(self.key_file)
        if not os.path.isfile(key_file):
            key_dir = os.path.dirname(key_file)
            tobiko.makedirs(key_dir)
            try:
                sh.local_execute(['ssh-keygen', '-f', key_file, '-P', ''])
            except sh.ShellCommandFailed:
                if not os.path.isfile(key_file):
                    raise
            else:
                assert os.path.isfile(key_file)
Beispiel #3
0
class AmphoraIPv4LoadBalancerStack(heat.HeatStackFixture):
    template = _hot.heat_template_file('octavia/load_balancer.yaml')

    vip_network = tobiko.required_fixture(_neutron.NetworkStackFixture)

    #: Floating IP network where the Neutron floating IP are created
    @property
    def floating_network(self) -> str:
        return self.vip_network.floating_network

    @property
    def has_floating_ip(self) -> bool:
        return bool(self.floating_network)

    ip_version = 4

    provider = 'amphora'

    @property
    def vip_subnet_id(self):
        if self.ip_version == 4:
            return self.vip_network.ipv4_subnet_id
        else:
            return self.vip_network.ipv6_subnet_id

    def wait_for_active_loadbalancer(self, timeout: tobiko.Seconds = None):
        octavia.wait_for_status(status_key=octavia.PROVISIONING_STATUS,
                                status=octavia.ACTIVE,
                                get_client=octavia.get_loadbalancer,
                                object_id=self.loadbalancer_id,
                                timeout=timeout)

    def wait_for_update_loadbalancer(self, timeout: tobiko.Seconds = None):
        octavia.wait_for_status(status_key=octavia.PROVISIONING_STATUS,
                                status=octavia.PENDING_UPDATE,
                                get_client=octavia.get_loadbalancer,
                                object_id=self.loadbalancer_id,
                                timeout=timeout)

    def wait_for_octavia_service(self,
                                 interval: tobiko.Seconds = None,
                                 timeout: tobiko.Seconds = None,
                                 client=None):
        for attempt in tobiko.retry(timeout=timeout,
                                    interval=interval,
                                    default_timeout=180.,
                                    default_interval=5.):
            try:
                octavia.list_amphorae(loadbalancer_id=self.loadbalancer_id,
                                      client=client)
            except octavia.OctaviaClientException as ex:
                LOG.debug(f"Error listing amphorae: {ex}")
                if attempt.is_last:
                    raise
                LOG.info('Waiting for the LB to become functional again...')
            else:
                LOG.info('Octavia service is available!')
                break
Beispiel #4
0
class DesignateZoneStackFixture(heat.HeatStackFixture):
    template = _hot.heat_template_file('designate/zone.yaml')

    @property
    def zone_name(self) -> str:
        return tobiko.get_fixture_name(self).lower() + '.'

    @property
    def zone_details(self) -> typing.Mapping[str, typing.Any]:
        return designate.get_designate_zone(self.zone_id)
Beispiel #5
0
class FlavorStackFixture(heat.HeatStackFixture):
    template = _hot.heat_template_file('nova/flavor.yaml')

    disk = None
    ephemeral = None
    extra_specs = None
    is_public = None
    name = None
    rxtx_factor = None
    swap = None
    vcpus = None
Beispiel #6
0
class QosPolicyStackFixture(heat.HeatStackFixture):
    """Heat stack with a QoS Policy and some QoS Policy Rules
    """
    has_qos_policy = True
    has_bwlimit = True
    has_dscp_marking = True
    bwlimit_kbps = CONF.tobiko.neutron.bwlimit_kbps
    bwlimit_burst_kbps = int(0.8 * bwlimit_kbps)
    direction = CONF.tobiko.neutron.direction
    dscp_mark = CONF.tobiko.neutron.dscp_mark

    #: Heat template file
    template = _hot.heat_template_file('neutron/qos.yaml')
Beispiel #7
0
class ServerStackFixture(heat.HeatStackFixture):

    #: Heat template file
    template = _hot.heat_template_file('nova/server.yaml')

    #: stack with the key pair for the server instance
    key_pair_stack = tobiko.required_setup_fixture(KeyPairStackFixture)

    #: stack with the internal where the server port is created
    network_stack = tobiko.required_setup_fixture(_neutron.NetworkStackFixture)

    #: Glance image used to create a Nova server instance
    image_fixture = None

    @property
    def image(self):
        return self.image_fixture.image_id

    @property
    def username(self):
        """username used to login to a Nova server instance"""
        return self.image_fixture.username

    @property
    def password(self):
        """password used to login to a Nova server instance"""
        return self.image_fixture.password

    # Stack used to create flavor for Nova server instance
    flavor_stack = None

    @property
    def flavor(self):
        """Flavor for Nova server instance"""
        return self.flavor_stack.flavor_id

    #: Whenever port security on internal network is enable
    port_security_enabled = False

    #: Security groups to be associated to network ports
    security_groups = []  # type: typing.List[str]

    @property
    def key_name(self):
        return self.key_pair_stack.key_name

    @property
    def network(self):
        return self.network_stack.network_id

    #: Floating IP network where the Neutron floating IP is created
    floating_network = CONF.tobiko.neutron.floating_network

    @property
    def has_floating_ip(self):
        """Whenever to allocate floating IP for the server"""
        return bool(self.floating_network)

    @property
    def ssh_client(self):
        return ssh.ssh_client(host=self.ip_address,
                              username=self.username,
                              password=self.password)

    @property
    def ssh_command(self):
        return ssh.ssh_command(host=self.ip_address, username=self.username)

    @property
    def ip_address(self):
        if self.has_floating_ip:
            return self.floating_ip_address
        else:
            return self.outputs.fixed_ips[0]['ip_address']

    #: Schedule on different host that this Nova server instance ID
    different_host = None

    #: Schedule on same host as this Nova server instance ID
    same_host = None

    @property
    def scheduler_hints(self):
        scheduler_hints = {}
        if self.different_host:
            scheduler_hints.update(different_host=self.different_host)
        if self.same_host:
            scheduler_hints.update(same_host=self.same_host)
        return scheduler_hints

    @property
    def server_details(self):
        return nova.get_server(self.server_id)

    @property
    def port_details(self):
        return neutron.get_port(self.port_id)

    def getDetails(self):
        # pylint: disable=W0212
        details = super(ServerStackFixture, self).getDetails()
        stack = self.get_stack()
        if stack:
            details[self.fixture_name + '.stack'] = (self.details_content(
                get_json=lambda: stack._info))
            if stack.stack_status == 'CREATE_COMPLETE':
                details[self.fixture_name +
                        '.server_details'] = (self.details_content(
                            get_json=lambda: self.server_details._info))
                details[self.fixture_name +
                        '.console_output'] = (self.details_content(
                            get_text=lambda: self.console_output))
        return details

    def details_content(self, **kwargs):
        return tobiko.details_content(content_id=self.fixture_name, **kwargs)

    max_console_output_length = 64 * 1024

    @property
    def console_output(self):
        return nova.get_console_output(server=self.server_id,
                                       length=self.max_console_output_length)
Beispiel #8
0
class NetworkStackFixture(heat.HeatStackFixture):
    """Heat stack for creating internal network with a router to external"""

    #: Heat template file
    template = _hot.heat_template_file('neutron/network.yaml')

    #: Disable port security by default for new network ports
    port_security_enabled = False

    @property
    def has_ipv4(self):
        """Whenever to setup IPv4 subnet"""
        return bool(CONF.tobiko.neutron.ipv4_cidr)

    @property
    def ipv4_cidr(self):
        if self.has_ipv4:
            return neutron.new_ipv4_cidr(seed=self.fixture_name)
        else:
            return None

    @property
    def has_ipv6(self):
        """Whenever to setup IPv6 subnet"""
        return bool(CONF.tobiko.neutron.ipv4_cidr)

    @property
    def ipv6_cidr(self):
        if self.has_ipv6:
            return neutron.new_ipv6_cidr(seed=self.fixture_name)
        else:
            return None

    @property
    def network_value_specs(self):
        """Extra network creation parameters"""
        return {}

    @property
    def gateway_network(self):
        """Floating IP network where the Neutron floating IPs are created"""
        return CONF.tobiko.neutron.floating_network

    ha = False

    @property
    def gateway_value_specs(self):
        value_specs = {}
        if self.has_l3_ha:
            value_specs.update(ha=(self.ha or False))
        return value_specs

    @property
    def has_gateway(self):
        """Whenever to setup gateway router"""
        return bool(self.gateway_network)

    @property
    def has_net_mtu(self):
        """Whenever can obtain network MTU value"""
        return neutron.has_networking_extensions('net-mtu')

    @property
    def has_l3_ha(self):
        """Whenever can obtain gateway router HA value"""
        return neutron.has_networking_extensions('l3-ha')

    @property
    def network_details(self):
        return neutron.get_network(self.network_id)

    @property
    def ipv4_subnet_details(self):
        return neutron.get_subnet(self.ipv4_subnet_id)

    @property
    def ipv4_subnet_cidr(self):
        return netaddr.IPNetwork(self.ipv4_subnet_details['cidr'])

    @property
    def ipv4_subnet_gateway_ip(self):
        return netaddr.IPAddress(self.ipv4_subnet_details['gateway_ip'])

    @property
    def ipv6_subnet_details(self):
        return neutron.get_subnet(self.ipv6_subnet_id)

    @property
    def ipv6_subnet_cidr(self):
        return netaddr.IPNetwork(self.ipv6_subnet_details['cidr'])

    @property
    def ipv6_subnet_gateway_ip(self):
        return netaddr.IPAddress(self.ipv6_subnet_details['gateway_ip'])

    @property
    def gateway_details(self):
        return neutron.get_router(self.gateway_id)

    @property
    def external_gateway_ips(self):
        fixed_ips = self.gateway_details['external_gateway_info'][
            'external_fixed_ips']
        return tobiko.select(
            netaddr.IPAddress(fixed_ip['ip_address'])
            for fixed_ip in fixed_ips)

    @property
    def ipv4_gateway_ports(self):
        return neutron.list_ports(fixed_ips='subnet_id=' + self.ipv4_subnet_id,
                                  device_id=self.gateway_id,
                                  network_id=self.network_id)

    @property
    def ipv6_gateway_ports(self):
        return neutron.list_ports(fixed_ips='subnet_id=' + self.ipv6_subnet_id,
                                  device_id=self.gateway_id,
                                  network_id=self.network_id)

    @property
    def external_geteway_ports(self):
        return neutron.list_ports(device_id=self.gateway_id,
                                  network_id=self.gateway_network_id)

    @property
    def ipv4_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.ipv4_gateway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def ipv6_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.ipv6_gateway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def external_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.external_geteway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def gateway_network_details(self):
        return neutron.get_network(self.gateway_network_id)
Beispiel #9
0
class SecurityGroupsFixture(heat.HeatStackFixture):
    """Heat stack with some security groups

    """
    #: Heat template file
    template = _hot.heat_template_file('neutron/security_groups.yaml')
Beispiel #10
0
class NetworkStackFixture(heat.HeatStackFixture):
    """Heat stack for creating internal network with a router to external"""

    #: Heat template file
    template = _hot.heat_template_file('neutron/network.yaml')

    #: Enable port security by default for new network ports
    port_security_enabled = True

    @property
    def has_ipv4(self):
        """Whenever to setup IPv4 subnet"""
        return bool(CONF.tobiko.neutron.ipv4_cidr)

    @property
    def ipv4_cidr(self):
        if self.has_ipv4:
            return neutron.new_ipv4_cidr(seed=self.fixture_name)
        else:
            return None

    @property
    def has_ipv6(self):
        """Whenever to setup IPv6 subnet"""
        return bool(CONF.tobiko.neutron.ipv6_cidr)

    @property
    def ipv6_cidr(self):
        if self.has_ipv6:
            return neutron.new_ipv6_cidr(seed=self.fixture_name)
        else:
            return None

    @property
    def network_value_specs(self):
        """Extra network creation parameters"""
        return {}

    floating_network_stack = tobiko.required_fixture(
        FloatingNetworkStackFixture)

    @property
    def floating_network(self):
        """Network ID where the Neutron floating IPs are created"""
        return self.floating_network_stack.network_id

    @property
    def gateway_network(self):
        """Network ID where gateway routes packages to"""
        return self.floating_network

    ha = False

    @property
    def gateway_value_specs(self):
        value_specs = {}
        if self.has_l3_ha:
            value_specs.update(ha=(self.ha or False))
        return value_specs

    @property
    def has_gateway(self):
        """Whenever to setup gateway router"""
        return bool(self.gateway_network)

    @property
    def has_net_mtu(self):
        """Whenever can obtain network MTU value"""
        return neutron.has_networking_extensions('net-mtu')

    @property
    def has_l3_ha(self):
        """Whenever can obtain gateway router HA value"""
        return neutron.has_networking_extensions('l3-ha')

    @property
    def network_details(self):
        return neutron.get_network(self.network_id)

    @property
    def ipv4_subnet_details(self):
        return neutron.get_subnet(self.ipv4_subnet_id)

    @property
    def ipv4_subnet_cidr(self):
        return netaddr.IPNetwork(self.ipv4_subnet_details['cidr'])

    @property
    def ipv4_subnet_gateway_ip(self):
        return netaddr.IPAddress(self.ipv4_subnet_details['gateway_ip'])

    @property
    def ipv4_dns_nameservers(self):
        nameservers = CONF.tobiko.neutron.ipv4_dns_nameservers
        if nameservers is None:
            nameservers = default_nameservers(ip_version=4)
        return ','.join(str(nameserver) for nameserver in nameservers)

    @property
    def ipv6_subnet_details(self):
        return neutron.get_subnet(self.ipv6_subnet_id)

    @property
    def ipv6_subnet_cidr(self):
        return netaddr.IPNetwork(self.ipv6_subnet_details['cidr'])

    @property
    def ipv6_subnet_gateway_ip(self):
        return netaddr.IPAddress(self.ipv6_subnet_details['gateway_ip'])

    @property
    def ipv6_dns_nameservers(self):
        nameservers = CONF.tobiko.neutron.ipv6_dns_nameservers
        if nameservers is None:
            nameservers = default_nameservers(ip_version=6)
        return ','.join(str(nameserver) for nameserver in nameservers)

    @property
    def gateway_details(self):
        return neutron.get_router(self.gateway_id)

    @property
    def external_gateway_ips(self):
        fixed_ips = self.gateway_details['external_gateway_info'][
            'external_fixed_ips']
        return tobiko.select(
            netaddr.IPAddress(fixed_ip['ip_address'])
            for fixed_ip in fixed_ips)

    @property
    def ipv4_gateway_ports(self):
        return neutron.list_ports(fixed_ips='subnet_id=' + self.ipv4_subnet_id,
                                  device_id=self.gateway_id,
                                  network_id=self.network_id)

    @property
    def ipv6_gateway_ports(self):
        return neutron.list_ports(fixed_ips='subnet_id=' + self.ipv6_subnet_id,
                                  device_id=self.gateway_id,
                                  network_id=self.network_id)

    @property
    def external_geteway_ports(self):
        return neutron.list_ports(device_id=self.gateway_id,
                                  network_id=self.gateway_network_id)

    @property
    def ipv4_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.ipv4_gateway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def ipv6_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.ipv6_gateway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def external_gateway_addresses(self):
        ips = tobiko.Selection()
        for port in self.external_geteway_ports:
            ips.extend(neutron.list_port_ip_addresses(port))
        return ips

    @property
    def gateway_network_details(self):
        return neutron.get_network(self.gateway_network_id)

    @property
    def neutron_required_quota_set(self) -> typing.Dict[str, int]:
        requirements = super().neutron_required_quota_set
        requirements['network'] += 1
        if self.has_ipv4:
            requirements['subnet'] += 1
        if self.has_ipv6:
            requirements['subnet'] += 1
        if self.has_gateway:
            requirements['router'] += 1
        return requirements

    def is_router_distributed(self) -> bool:
        if self.has_gateway:
            tobiko.setup_fixture(self)
            return bool(self.gateway_details.get('distributed'))
        else:
            return False

    @classmethod
    def skip_if_router_is_distributed(cls, reason: str = None):
        fixture = tobiko.get_fixture(cls)
        if reason is None:
            reason = "Distributed router is not supported"
        return tobiko.skip_if(reason=reason,
                              predicate=fixture.is_router_distributed)
Beispiel #11
0
class HttpRoundRobinAmphoraIpv4Listener(heat.HeatStackFixture):
    template = _hot.heat_template_file('octavia/listener.yaml')

    loadbalancer = tobiko.required_fixture(AmphoraIPv4LoadBalancerStack)

    lb_port = 80

    lb_protocol = 'HTTP'

    @property
    def loadbalancer_id(self):
        return self.loadbalancer.loadbalancer_id

    @property
    def loadbalancer_provider(self):
        return self.loadbalancer.provider

    # Pool attributes
    pool_protocol = 'HTTP'

    lb_algorithm = 'ROUND_ROBIN'

    # healthmonitor attributes
    hm_type = 'HTTP'

    hm_delay = 3

    hm_max_retries = 4

    hm_timeout = 3

    #: whenever to create the health monitor
    has_monitor = True

    @property
    def listener_id(self):
        return self.listener.listener_id

    def wait_for_active_members(self):
        """Wait for all pool members to be active"""

        for member in octavia.list_members(pool_id=self.pool_id):
            self.wait_for_active_member(pool_id=self.pool_id,
                                        member_id=member['id'])

    def wait_for_active_member(self, pool_id, member_id, **kwargs):
        """Wait for the member to be active

        Waits for the member to have an ACTIVE provisioning status.

        :param member_id: the member id.
        :param pool_id: the pool id.
        """
        octavia.wait_for_status(status_key=octavia.PROVISIONING_STATUS,
                                status=octavia.ACTIVE,
                                get_client=octavia.get_member,
                                object_id=pool_id,
                                member_id=member_id,
                                **kwargs)

    def wait_for_members_to_be_reachable(self,
                                         interval: tobiko.Seconds = None,
                                         timeout: tobiko.Seconds = None):

        members = [self.server_stack, self.other_server_stack]

        if len(members) < 1:
            return

        # Wait for members to be reachable from localhost
        last_reached_id = 0
        for attempt in tobiko.retry(timeout=timeout,
                                    interval=interval,
                                    default_interval=5.,
                                    default_timeout=members[0].wait_timeout):
            try:
                for member in members[last_reached_id:]:
                    octavia.check_members_balanced(
                        members_count=1,
                        ip_address=member.ip_address,
                        protocol=self.lb_protocol,
                        port=self.lb_port,
                        requests_count=1)
                    last_reached_id += 1  # prevent retrying same member again
            except sh.ShellCommandFailed:
                if attempt.is_last:
                    raise
                LOG.info(
                    "Waiting for members to have HTTP service available...")
                continue
            else:
                break
        else:
            raise RuntimeError("Members couldn't be reached!")

    # Members attributes
    server_stack = tobiko.required_fixture(_ubuntu.UbuntuServerStackFixture)

    other_server_stack = tobiko.required_fixture(
        OctaviaOtherServerStackFixture)

    application_port = 80

    ip_version = 4

    @property
    def pool_id(self):
        return self.pool.pool_id

    @property
    def subnet_id(self):
        network_stack = self.server_stack.network_stack
        if self.ip_version == 4:
            return network_stack.ipv4_subnet_id
        else:
            return network_stack.ipv6_subnet_id

    @property
    def member_address(self) -> str:
        return self.get_member_address(self.server_stack)

    @property
    def other_member_address(self) -> str:
        return self.get_member_address(self.other_server_stack)

    def get_member_address(self, server_stack):
        return str(server_stack.find_fixed_ip(ip_version=self.ip_version))