Beispiel #1
0
class DiskDevice(models.Model):
    class Meta(object):
        db_table = 'devops_diskdevice'
        app_label = 'devops'

    node = models.ForeignKey('Node', null=False)
    volume = models.ForeignKey('Volume', null=True)
    device = choices('disk', 'cdrom')
    type = choices('file')
    bus = choices('virtio')
    target_dev = models.CharField(max_length=255, null=False)

    @classmethod
    def node_attach_volume(cls,
                           node,
                           volume,
                           device='disk',
                           type='file',
                           bus='virtio',
                           target_dev=None):
        """Attach volume to node

        :rtype : DiskDevice
        """
        return cls.objects.create(device=device,
                                  type=type,
                                  bus=bus,
                                  target_dev=target_dev
                                  or node.next_disk_name(),
                                  volume=volume,
                                  node=node)
Beispiel #2
0
class Interface(models.Model):
    class Meta(object):
        db_table = 'devops_interface'
        app_label = 'devops'

    node = models.ForeignKey('Node')
    l2_network_device = models.ForeignKey('L2NetworkDevice', null=True)
    label = models.CharField(max_length=255, null=True)
    mac_address = models.CharField(max_length=255, unique=True, null=False)
    type = models.CharField(max_length=255, null=False)
    model = choices('virtio', 'e1000', 'pcnet', 'rtl8139', 'ne2k_pci')

    # LEGACY, for fuel-qa compatibility if MULTIPLE_NETWORKS enabled
    @property
    def network(self):
        return self.l2_network_device

    @property
    def target_dev(self):
        return self.label

    @property
    def addresses(self):
        return self.address_set.all()

    def add_address(self):
        ip = self.l2_network_device.address_pool.next_ip()
        Address.objects.create(
            ip_address=str(ip),
            interface=self,
        )

    @staticmethod
    def interface_create(l2_network_device,
                         node,
                         label,
                         type='network',
                         mac_address=None,
                         model='virtio'):
        """Create interface

        :rtype : Interface
        """
        interface = Interface.objects.create(
            l2_network_device=l2_network_device,
            node=node,
            label=label,
            type=type,
            mac_address=mac_address or generate_mac(),
            model=model)
        if (interface.l2_network_device
                and interface.l2_network_device.address_pool is not None):
            interface.add_address()
        return interface
Beispiel #3
0
class Interface(models.Model):
    class Meta(object):
        db_table = 'devops_interface'

    network = models.ForeignKey('Network')
    node = models.ForeignKey('Node')
    mac_address = models.CharField(max_length=255, unique=True, null=False)
    type = models.CharField(max_length=255, null=False)
    model = choices('virtio', 'e1000', 'pcnet', 'rtl8139', 'ne2k_pci')

    @property
    def target_dev(self):
        return self.node.driver.node_get_interface_target_dev(
            self.node, self.mac_address)

    @property
    def addresses(self):
        return self.address_set.all()

    @staticmethod
    def interface_create(network,
                         node,
                         type='network',
                         mac_address=None,
                         model='virtio',
                         interface_map=None):
        """Create interface

        :rtype : Interface
        """
        if interface_map is None:
            interface_map = {}
        interfaces = []

        def _create(mac_addr=None):
            interface = Interface.objects.create(network=network,
                                                 node=node,
                                                 type=type,
                                                 mac_address=mac_addr
                                                 or generate_mac(),
                                                 model=model)
            Address.objects.create(ip_address=str(network.next_ip()),
                                   interface=interface)
            return interface

        if interface_map:
            if len(interface_map[network.name]) > 0:
                for _ in interface_map[network.name]:
                    interfaces.append(_create())
                return interfaces
        else:
            return _create(mac_address)
Beispiel #4
0
class Interface(ParamedModel):
    class Meta(object):
        db_table = 'devops_interface'
        app_label = 'devops'

    node = models.ForeignKey('Node')
    l2_network_device = models.ForeignKey('L2NetworkDevice', null=True)
    label = models.CharField(max_length=255, null=True)
    mac_address = models.CharField(max_length=255, unique=True, null=False)
    type = models.CharField(max_length=255, null=False)
    model = choices('virtio', 'e1000', 'pcnet', 'rtl8139', 'ne2k_pci')

    @property
    def driver(self):
        return self.node.driver

    # LEGACY, for fuel-qa compatibility if MULTIPLE_NETWORKS enabled
    @property
    def network(self):
        return self.l2_network_device

    @property
    def target_dev(self):
        return self.label

    @property
    def addresses(self):
        return self.address_set.all()

    @property
    def network_config(self):
        return self.node.networkconfig_set.get(label=self.label)

    def define(self):
        self.save()

    def remove(self):
        self.delete()

    def add_address(self):
        ip = self.l2_network_device.address_pool.next_ip()
        Address.objects.create(
            ip_address=str(ip),
            interface=self,
        )

    @property
    def is_blocked(self):
        """Show state of interface"""
        return False

    def block(self):
        """Block traffic on interface"""
        pass

    def unblock(self):
        """Unblock traffic on interface"""
        pass

    @classmethod
    def interface_create(cls,
                         l2_network_device,
                         node,
                         label,
                         if_type='network',
                         mac_address=None,
                         model='virtio'):
        """Create interface

        :rtype : Interface
        """
        interface = cls.objects.create(l2_network_device=l2_network_device,
                                       node=node,
                                       label=label,
                                       type=if_type,
                                       mac_address=mac_address
                                       or generate_mac(),
                                       model=model)
        if (interface.l2_network_device
                and interface.l2_network_device.address_pool is not None):
            interface.add_address()
        return interface
Beispiel #5
0
class Network(DriverModel):
    class Meta:
        unique_together = ('name', 'environment')
        db_table = 'devops_network'

    environment = models.ForeignKey('Environment', null=True)
    name = models.CharField(max_length=255, unique=False, null=False)
    uuid = models.CharField(max_length=255)
    has_dhcp_server = models.BooleanField()
    has_pxe_server = models.BooleanField()
    has_reserved_ips = models.BooleanField(default=True)
    tftp_root_dir = models.CharField(max_length=255)
    forward = choices('nat',
                      'route',
                      'bridge',
                      'private',
                      'vepa',
                      'passthrough',
                      'hostdev',
                      null=True)
    # 'ip_network' should be renamed to 'cidr'
    ip_network = models.CharField(max_length=255, unique=True)

    _iterhosts = None

    # Dirty trick. It should be placed on instance level of Environment class.
    default_pool = None

    @property
    def ip(self):
        """Return IPNetwork representation of self.ip_network field.

        :return: IPNetwork()
        """
        return IPNetwork(self.ip_network)

    @property
    def interfaces(self):
        return self.interface_set.all()

    @property
    def ip_pool_start(self):
        return IPNetwork(self.ip_network)[2]

    @property
    def ip_pool_end(self):
        return IPNetwork(self.ip_network)[-2]

    @property
    def netmask(self):
        return IPNetwork(self.ip_network).netmask

    @property
    def default_gw(self):
        return IPNetwork(self.ip_network)[1]

    def next_ip(self):
        while True:
            self._iterhosts = self._iterhosts or IPNetwork(
                self.ip_network).iterhosts()
            ip = self._iterhosts.next()
            if ip < self.ip_pool_start or ip > self.ip_pool_end:
                continue
            if not Address.objects.filter(interface__network=self,
                                          ip_address=str(ip)).exists():
                return ip

    def bridge_name(self):
        return self.driver.network_bridge_name(self)

    def define(self):
        self.driver.network_define(self)
        self.save()

    def start(self):
        self.create(verbose=False)

    def create(self, verbose=False):
        if verbose or not self.driver.network_active(self):
            self.driver.network_create(self)

    def destroy(self):
        self.driver.network_destroy(self)

    def erase(self):
        self.remove(verbose=False)

    def remove(self, verbose=False):
        if verbose or self.uuid:
            if verbose or self.driver.network_exists(self):
                if self.driver.network_active(self):
                    self.driver.network_destroy(self)
                self.driver.network_undefine(self)
        self.delete()

    @classmethod
    def create_network_pool(cls, networks, prefix):
        """Create network pool

        :rtype : IpNetworksPool
        """
        pool = IpNetworksPool(networks=networks, prefix=prefix)
        pool.set_allocated_networks(cls.get_driver().get_allocated_networks())
        return pool

    @classmethod
    def _get_default_pool(cls):
        """Get default pool. If it does not exists, create 10.0.0.0/16 pool.

        :rtype : IpNetworksPool
        """
        cls.default_pool = cls.default_pool or Network.create_network_pool(
            networks=[IPNetwork('10.0.0.0/16')], prefix=24)
        return cls.default_pool

    @classmethod
    @transaction.commit_on_success
    def _safe_create_network(cls,
                             name,
                             environment=None,
                             pool=None,
                             has_dhcp_server=True,
                             has_pxe_server=False,
                             forward='nat'):
        allocated_pool = pool or cls._get_default_pool()
        while True:
            try:
                ip_network = allocated_pool.next()
                if not cls.objects.filter(ip_network=str(ip_network)).exists():
                    return cls.objects.create(environment=environment,
                                              name=name,
                                              ip_network=ip_network,
                                              has_pxe_server=has_pxe_server,
                                              has_dhcp_server=has_dhcp_server,
                                              forward=forward)
            except IntegrityError:
                transaction.rollback()

    @classmethod
    def network_create(cls,
                       name,
                       environment=None,
                       ip_network=None,
                       pool=None,
                       has_dhcp_server=True,
                       has_pxe_server=False,
                       forward='nat'):
        """Create network

        :rtype : Network
        """
        if ip_network:
            return cls.objects.create(environment=environment,
                                      name=name,
                                      ip_network=ip_network,
                                      has_pxe_server=has_pxe_server,
                                      has_dhcp_server=has_dhcp_server,
                                      forward=forward)
        return cls._safe_create_network(environment=environment,
                                        forward=forward,
                                        has_dhcp_server=has_dhcp_server,
                                        has_pxe_server=has_pxe_server,
                                        name=name,
                                        pool=pool)

    @classmethod
    def create_networks(cls,
                        environment,
                        network_names=None,
                        has_dhcp=False,
                        has_pxe=False,
                        forward='nat',
                        pool=None):
        """Create several networks

        :param environment: Environment
        :param network_names: List
        :param has_dhcp: Bool
        :param has_pxe: Bool
        :param forward: String
        :param pool: IpNetworksPool
            :rtype : List
        """
        if network_names is None:
            network_names = settings.DEFAULT_INTERFACE_ORDER.split(',')
        networks = []
        for name in network_names:
            net = cls.network_create(name=name,
                                     environment=environment,
                                     has_dhcp_server=has_dhcp,
                                     has_pxe_server=has_pxe,
                                     forward=forward,
                                     pool=pool)
            networks.append(net)
        return networks
Beispiel #6
0
class Interface(base.ParamedModel):
    """Describes a network interface configuration

    Specify the abstract label of the interface (you can use labels
    that match the real interface names or use any suitable names).

    'l2_network_device' describes the switch name (virtual or hardware)
    to which the interface is connected.

    'features' is a json list with any strings you want use to mark
    interfaces with specific features and use these marks in 3rd-party
    libraries to perform highlevel configuration of the right interfaces
    for your product.

    Template example (interfaces):
    ---------------------------------
      - name: some_node_name
        params:
          ...
          interfaces:
            - label: iface0
              l2_network_device: admin
            - label: iface1
              l2_network_device: data
              mac_address: !os_env IFACE_MAC_ADDRESS, 00:11:22:33:44:55
              features: ['dpdk', 'dpdk_pci: 0000:05:00.1']
    """
    class Meta(object):
        db_table = 'devops_interface'
        app_label = 'devops'

    node = models.ForeignKey('Node')
    l2_network_device = models.ForeignKey('L2NetworkDevice', null=True)
    label = models.CharField(max_length=255, null=True)
    mac_address = models.CharField(max_length=255, unique=True, null=False)
    type = models.CharField(max_length=255, null=False)
    model = base.choices('virtio', 'e1000', 'pcnet', 'rtl8139', 'ne2k_pci')
    features = base.ParamField(default=[])

    @property
    def driver(self):
        return self.node.driver

    # LEGACY, for fuel-qa compatibility if MULTIPLE_NETWORKS enabled
    @property
    def network(self):
        return self.l2_network_device

    @property
    def target_dev(self):
        return self.label

    @property
    def addresses(self):
        return self.address_set.all()

    @property
    def network_config(self):
        return self.node.networkconfig_set.get(label=self.label)

    def define(self):
        self.save()

    def remove(self):
        self.delete()

    def add_address(self):
        """Assign an IP address to the interface

        Try to get an IP from reserved IP with name '<group>_<node>'
        , or generate next IP if reserved IP wasn't found.
        Next IP is generated from the DHCP ip_range, or from the
        network range [+2:-2] of all available addresses in the address pool.
        """
        reserved_ip_name = helpers.underscored(self.node.group.name,
                                               self.node.name)
        reserved_ip = self.l2_network_device.address_pool.get_ip(
            reserved_ip_name)
        ip = reserved_ip or self.l2_network_device.address_pool.next_ip()
        Address.objects.create(
            ip_address=str(ip),
            interface=self,
        )

    @property
    def is_blocked(self):
        """Show state of interface"""
        return False

    def block(self):
        """Block traffic on interface"""
        pass

    def unblock(self):
        """Unblock traffic on interface"""
        pass

    @classmethod
    def interface_create(cls, l2_network_device, node, label,
                         if_type='network', mac_address=None, model='virtio',
                         features=None):
        """Create interface

        :rtype : Interface
        """
        interface = cls.objects.create(
            l2_network_device=l2_network_device,
            node=node,
            label=label,
            type=if_type,
            mac_address=mac_address or helpers.generate_mac(),
            model=model,
            features=features or [])
        if (interface.l2_network_device and
                interface.l2_network_device.address_pool is not None):
            interface.add_address()
        return interface
Beispiel #7
0
class Node(DriverModel):
    class Meta:
        unique_together = ('name', 'environment')
        db_table = 'devops_node'

    environment = models.ForeignKey('Environment', null=True)
    name = models.CharField(max_length=255, unique=False, null=False)
    uuid = models.CharField(max_length=255)
    hypervisor = choices('kvm')
    os_type = choices('hvm')
    architecture = choices('x86_64', 'i686')
    boot = models.CharField(max_length=255, null=False, default=json.dumps([]))
    metadata = models.CharField(max_length=255, null=True)
    role = models.CharField(max_length=255, null=True)
    vcpu = models.PositiveSmallIntegerField(null=False, default=1)
    memory = models.IntegerField(null=False, default=1024)
    has_vnc = models.BooleanField(null=False, default=True)

    def next_disk_name(self):
        disk_names = ('sd' + c for c in list('abcdefghijklmnopqrstuvwxyz'))
        while True:
            disk_name = disk_names.next()
            if not self.disk_devices.filter(target_dev=disk_name).exists():
                return disk_name

    def get_vnc_port(self):
        return self.driver.node_get_vnc_port(node=self)

    @property
    def disk_devices(self):
        return self.diskdevice_set.all()

    @property
    def interfaces(self):
        return self.interface_set.order_by('id')

    @property
    def vnc_password(self):
        return settings.VNC_PASSWORD

    def interface_by_name(self, name):
        self.interfaces.filter(name=name)

    def get_ip_address_by_network_name(self, name, interface=None):
        interface = interface or self.interface_set.filter(
            network__name=name).order_by('id')[0]
        return interface.address_set.get(interface=interface).ip_address

    def remote(self, network_name, login, password=None, private_keys=None):
        """Create SSH-connection to the network

        :rtype : SSHClient
        """
        return SSHClient(self.get_ip_address_by_network_name(network_name),
                         username=login,
                         password=password,
                         private_keys=private_keys)

    def send_keys(self, keys):
        self.driver.node_send_keys(self, keys)

    def await (self, network_name, timeout=120, by_port=22):
        _wait(lambda: _tcp_ping(
            self.get_ip_address_by_network_name(network_name), by_port),
              timeout=timeout)

    def define(self):
        self.driver.node_define(self)
        self.save()

    def start(self):
        self.create(verbose=False)

    def create(self, verbose=False):
        if verbose or not self.driver.node_active(self):
            self.driver.node_create(self)

    def destroy(self, verbose=False):
        if verbose or self.driver.node_active(self):
            self.driver.node_destroy(self)

    def erase(self):
        self.remove(verbose=False)

    def remove(self, verbose=False):
        if verbose or self.uuid:
            if verbose or self.driver.node_exists(self):
                self.destroy(verbose=False)
                self.driver.node_undefine(self, undefine_snapshots=True)
        self.delete()

    def suspend(self, verbose=False):
        if verbose or self.driver.node_active(self):
            self.driver.node_suspend(self)

    def resume(self, verbose=False):
        if verbose or self.driver.node_active(self):
            self.driver.node_resume(self)

    def has_snapshot(self, name):
        return self.driver.node_snapshot_exists(node=self, name=name)

    def snapshot(self, name=None, force=False, description=None):
        if force and self.has_snapshot(name):
            self.driver.node_delete_snapshot(node=self, name=name)
        self.driver.node_create_snapshot(node=self,
                                         name=name,
                                         description=description)

    def revert(self, name=None, destroy=True):
        if destroy:
            self.destroy(verbose=False)
        if self.has_snapshot(name):
            self.driver.node_revert_snapshot(node=self, name=name)
        else:
            print('Domain snapshot for {0} node not found: no domain '
                  'snapshot with matching'
                  ' name {1}'.format(self.name, name))

    def get_snapshots(self):
        return self.driver.node_get_snapshots(node=self)

    def erase_snapshot(self, name):
        self.driver.node_delete_snapshot(node=self, name=name)

    def set_vcpu(self, vcpu):
        """Set vcpu count on node

        param: vcpu: Integer
            :rtype : None
        """
        if vcpu != self.vcpu:
            self.vcpu = vcpu
            self.driver.node_set_vcpu(node=self, vcpu=vcpu)
            self.save()

    def set_memory(self, memory):
        """Set memory size on node

        param: memory: Integer
            :rtype : None
        """
        if memory != self.memory:
            self.memory = memory
            self.driver.node_set_memory(node=self, memory=memory * 1024)
            self.save()

    def attach_to_networks(self, network_names=None):
        """Attache node to several networks


        param: network_names: List
            :rtype : None
        """
        if network_names is None:
            network_names = settings.DEFAULT_INTERFACE_ORDER.split(',')
        networks = self.environment.get_networks(name=network_names)
        self.environment.create_interfaces(networks=networks, node=self)

    def attach_disks(self,
                     disknames_capacity=None,
                     format='qcow2',
                     device='disk',
                     bus='virtio',
                     force_define=False):
        """Attach several disks to node


        param: disknames_capacity: Dict
        param: format: String
        param: device: String
        param: bus: String
        param: force_define: Bool
            :rtype : None
        """
        if disknames_capacity is None:
            disknames_capacity = {
                'system': 50 * 1024**3,
                'swift': 50 * 1024**3,
                'cinder': 50 * 1024**3,
            }

        for diskname, capacity in disknames_capacity.iteritems():
            self.attach_disk(name=diskname,
                             capacity=capacity,
                             force_define=force_define)

    def attach_disk(self,
                    name,
                    capacity,
                    format='qcow2',
                    device='disk',
                    bus='virtio',
                    force_define=False):
        """Attach disk to node


        param: disknames_capacity: Dict
        param: format: String
        param: device: String
        param: bus: String
        param: force_define: Bool
            :rtype : DiskDevice
        """
        vol_name = "%s-%s" % (self.name, name)
        disk = self.environment.add_empty_volume(node=self,
                                                 name=vol_name,
                                                 capacity=capacity,
                                                 device=device,
                                                 bus=bus)
        if force_define:
            disk.volume.define()
        return disk

    @classmethod
    def node_create(cls,
                    name,
                    environment=None,
                    role=None,
                    vcpu=1,
                    memory=1024,
                    has_vnc=True,
                    metadata=None,
                    hypervisor='kvm',
                    os_type='hvm',
                    architecture='x86_64',
                    boot=None):
        """Create node

        :rtype : Node
        """
        if not boot:
            boot = ['network', 'cdrom', 'hd']
        node = cls.objects.create(name=name,
                                  environment=environment,
                                  role=role,
                                  vcpu=vcpu,
                                  memory=memory,
                                  has_vnc=has_vnc,
                                  metadata=metadata,
                                  hypervisor=hypervisor,
                                  os_type=os_type,
                                  architecture=architecture,
                                  boot=json.dumps(boot))
        return node
Beispiel #8
0
class Interface(base.ParamedModel):
    class Meta(object):
        db_table = 'devops_interface'
        app_label = 'devops'

    node = models.ForeignKey('Node')
    l2_network_device = models.ForeignKey('L2NetworkDevice', null=True)
    label = models.CharField(max_length=255, null=True)
    mac_address = models.CharField(max_length=255, unique=True, null=False)
    type = models.CharField(max_length=255, null=False)
    model = base.choices('virtio', 'e1000', 'pcnet', 'rtl8139', 'ne2k_pci')
    features = base.ParamField(default=[])

    @property
    def driver(self):
        return self.node.driver

    # LEGACY, for fuel-qa compatibility if MULTIPLE_NETWORKS enabled
    @property
    def network(self):
        return self.l2_network_device

    @property
    def target_dev(self):
        return self.label

    @property
    def addresses(self):
        return self.address_set.all()

    @property
    def network_config(self):
        return self.node.networkconfig_set.get(label=self.label)

    def define(self):
        self.save()

    def remove(self):
        self.delete()

    def add_address(self):
        """Assign an IP address to the interface

        Try to get an IP from reserved IP with name '<group>_<node>'
        , or generate next IP if reserved IP wasn't found.
        Next IP is generated from the DHCP ip_range, or from the
        network range [+2:-2] of all available addresses in the address pool.
        """
        reserved_ip_name = helpers.underscored(self.node.group.name,
                                               self.node.name)
        reserved_ip = self.l2_network_device.address_pool.get_ip(
            reserved_ip_name)
        ip = reserved_ip or self.l2_network_device.address_pool.next_ip()
        Address.objects.create(
            ip_address=str(ip),
            interface=self,
        )

    @property
    def is_blocked(self):
        """Show state of interface"""
        return False

    def block(self):
        """Block traffic on interface"""
        pass

    def unblock(self):
        """Unblock traffic on interface"""
        pass

    @classmethod
    def interface_create(cls,
                         l2_network_device,
                         node,
                         label,
                         if_type='network',
                         mac_address=None,
                         model='virtio',
                         features=None):
        """Create interface

        :rtype : Interface
        """
        interface = cls.objects.create(l2_network_device=l2_network_device,
                                       node=node,
                                       label=label,
                                       type=if_type,
                                       mac_address=mac_address
                                       or helpers.generate_mac(),
                                       model=model,
                                       features=features or [])
        if (interface.l2_network_device
                and interface.l2_network_device.address_pool is not None):
            interface.add_address()
        return interface