Exemple #1
0
class Cloubed():

    """ Cloubed main class """

    __metaclass__ = Singleton

    def __init__(self, conf_loader=None):

        #
        # connection to the hypervisor
        #
        
        self.ctl = VirtController()
        if self.ctl == None:
            logging.error("Failed to open connection to the hypervisor")
            sys.exit(1)

        #
        # EventManager, None at the beginning. Initialized by
        # self.launch_event_manager() in self.wait_event()
        #
        self._event_manager = None
        
        #
        # parse configuration file
        #
        if conf_loader:
            self._conf_loader = conf_loader
        else:
            configuration_filename = os.path.join(os.getcwd(), "cloubed.yaml")
            self._conf_loader = ConfigurationLoader(configuration_filename)
        self._conf = Configuration(self._conf_loader)
        self._name = self._conf.testbed
    
        #
        # initialize storage pools
        #    
        self._storage_pools = []
        for storage_pool_conf in self._conf.storage_pools:
            logging.info("initializing storage pool {name}" \
                             .format(name=storage_pool_conf.name))
            self._storage_pools.append(StoragePool(self,
                                                   storage_pool_conf))
    
        #
        # initialize storage volumes
        #
        self._storage_volumes = []
        for storage_volume_conf in self._conf.storage_volumes:
            logging.info("initializing storage volume {name}" \
                             .format(name=storage_volume_conf.name))
            self._storage_volumes.append(StorageVolume(self,
                                                       storage_volume_conf))
    
        #
        # initialize networks
        #
        self._networks = []
        for network_conf in self._conf.networks:
            logging.info("initializing network {name}" \
                             .format(name=network_conf.name))
            self._networks.append(Network(self,
                                          network_conf))

        #
        # initialize domain and templates
        #
        self._domains = []
        for domain_conf in self._conf.domains:
            logging.info("initializing domain {name}" \
                             .format(name=domain_conf.name))
            self._domains.append(Domain(self,
                                        domain_conf))

        #
        # initialize http server, arbitrary select first host ip
        # found in cloubed yaml file
        #
        self._http_server = HTTPServer()

    def storage_pools(self):

        """ Returns the list of storage pools names """

        return [ storage_pool.name \
                 for storage_pool in self._storage_pools ]

    def storage_volumes(self):

        """ Returns the list of storage volumes names """

        return [ storage_volume.name \
                 for storage_volume in self._storage_volumes ]

    def networks(self):

        """ Returns the list of networks names """

        return [ network.name for network in self._networks ]

    def domains(self):

        """ Returns the list of domains names """

        return [ domain.name for domain in self._domains ]

    def get_domain_by_name(self, name):

        """Returns the Domain object of the testbed with the name in parameter.

           :param string name: the name of the domain to find
           :exceptions CloubedException:
               * the domain could not be found in the testbed
        """

        for domain in self._domains:
            if domain.name == name:
                return domain

        # domain not found
        raise CloubedException("domain {domain} not found in configuration" \
                                   .format(domain=name))

    def get_domain_by_libvirt_name(self, libvirt_name):

        """Returns the Domain object of the testbed with the libvirt name in
           parameter.

           :param string libvirt_name: the name in libvirt of the domain to find
           :exceptions CloubedException:
               * the domain could not be found in the testbed
        """

        for domain in self._domains:
            if domain.libvirt_name == libvirt_name:
                return domain

        # domain not found
        raise CloubedException("domain {domain} not found in configuration" \
                                   .format(domain=libvirt_name))

    def get_network_by_name(self, name):

        """
            Returns the Network object whose name is given in parameter. Raises
            exception if not found.
        """

        for network in self._networks:
            if network.name == name:
                return network

        # network not found
        raise CloubedException("network {network} not found in configuration"
                                   .format(network=name))

    def get_storage_volume_by_name(self, name):

        """
            Returns the StorageVolume object whose name is given in parameter.
            Raises exception if not found.
        """

        for storage_volume in self._storage_volumes:
            if storage_volume.name == name:
                return storage_volume

        # storage volume not found
        raise CloubedException("storage volume {storage_volume} not found in " \
                               "configuration".format(storage_volume=name))

    def get_storage_pool_by_name(self, name):

        """
            Returns the StoragePool object whose name is given in parameter.
            Raises exception if not found.
        """

        for storage_pool in self._storage_pools:
            if storage_pool.name == name:
                return storage_pool

        # storage pool not found
        raise CloubedException("storage pool {storage_pool} not found in " \
                               "configuration".format(storage_pool=name))

    def get_templates_dict(self, domain_name):

        """Returns the dict with all variables that could be used in a template
           for a domain.

           :param string domain_name: the name of the domain
           :exceptions CloubedException:
               * the domain could not be found in the testbed
        """

        if domain_name not in self.domains():
            raise CloubedException("domain {domain} not found in " \
                                   "configuration" \
                                       .format(domain=domain_name))

        templates_dict = self._conf.get_templates_dict(domain_name)
        return templates_dict

    def serve_http(self, address):
        
        """ server_http: """

        if self._http_server is not None:
            if not self._http_server.launched():
                logging.debug("launching HTTP server on address {address}" \
                                  .format(address=address))
                self._http_server.launch(address)

    def launch_event_manager(self):

        """ Launch event manager thread unless already done """

        if self._event_manager is None:
            self._event_manager = EventManager(self)

    def gen_file(self, domain_name, template_name):

        """ gen_file: """

        templates_dict = self.get_templates_dict(domain_name)

        domain = self.get_domain_by_name(domain_name)
        domain_template = domain.get_template_by_name(template_name)
        domain_template.render(templates_dict)

    def boot_vm(self, domain_name,
                bootdev="hd",
                overwrite_disks=[],
                recreate_networks=[]):

        """ boot_vm: """

        domain = self.get_domain_by_name(domain_name)

        #
        # manage disks
        #

        # build list of storage volumes to overwrite

        if type(overwrite_disks) == bool:
            if overwrite_disks == True:
                overwrite_disks = domain.get_storage_volumes_names()
            else:
                overwrite_disks = []
        else:
            # type(overwrite_disks) is list
            # remove non-existing disks and log warning
            domain_disks = domain.get_storage_volumes_names()
            for disk in set(overwrite_disks) - set(domain_disks):
                logging.warning("domain {domain} does not have disk " \
                                "{disk}, removing it of disks to " \
                                "overwrite" \
                                    .format(domain=domain.name,
                                            disk=disk))
                overwrite_disks.remove(disk)

        logging.debug("disks to overwrite for domain {domain}: {disks}" \
                          .format(domain=domain.name,
                                  disks=str(overwrite_disks)))

        for storage_volume in domain.get_storage_volumes():
            #if not storage_volume.created(): #useless?
            if storage_volume.name in overwrite_disks:
                overwrite_storage_volume = True
            else:
                overwrite_storage_volume = False
            storage_volume.storage_pool.create()
            storage_volume.create(overwrite_storage_volume)


        #
        # manage networks
        #

        # build list of networks to recreate

        if type(recreate_networks) == bool:
            if recreate_networks == True:
                recreate_networks = domain.get_networks_names()
            else:
                recreate_networks = []
        else:
            # type(recreate_networks) is list
            # remove non-existing networks and log warning
            domain_networks = domain.get_networks_names()
            for network in set(recreate_networks) - set(domain_networks):
                logging.warning("domain {domain} is not connected to " \
                                "network {network}, removing it of " \
                                "networks to recreate" \
                                    .format(domain=domain.name,
                                            network=network))
                recreate_networks.remove(network)

        logging.debug("networks to recreate for domain {domain}: " \
                      "{networks}" \
                          .format(domain=domain.name,
                                  networks=str(recreate_networks)))


        for network in domain.get_networks():
            #if not network.created(): #useless?
            if network.name in recreate_networks:
                recreate_network = True
            else:
                recreate_network = False
            network.create(recreate_network)

        #
        # manage domain
        #

        domain.create(bootdev)

        if domain.graphics in ["spice", "vnc"]:
            infos = domain.get_infos()
            logging.info("{type} console of domain {domain} available on port " \
                         "{port}".format(type=infos['console'],
                                         domain=domain.name,
                                         port=infos['port']))

    def shutdown(self, domain_name):

        """ Shutdown a specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.shutdown()

    def destroy(self, domain_name):

        """ Destroy a specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.destroy()

    def reboot(self, domain_name):

        """ Reboot a specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.reboot()

    def reset(self, domain_name):

        """ Reset a specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.reset()

    def suspend(self, domain_name):

        """ Suspend-to-RAM (ACPI S3 state) a specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.suspend()

    def resume(self, domain_name):

        """ Resume a previously suspended specific domain """

        domain = self.get_domain_by_name(domain_name)
        domain.resume()

    def create_network(self, network_name, recreate):

        """ Create network in Cloubed """
        network = self.get_network_by_name(network_name)
        network.create(recreate)

    def wait_event(self, domain_name,
                   event_type, event_detail,
                   enable_http=False):

        """ wait_event: """

        # search the domain
        domain = self.get_domain_by_name(domain_name)

        if enable_http:
            address = domain.get_first_host_ip()
            if address is not None:
                self.serve_http(address)
            else:
                logging.debug("HTTP server not launched because no host IP " \
                              "address on networks connected to domain " \
                              "{domain}".format(domain=domain_name))

        if event_type != 'tcp':

            # launch event manager tread
            self.launch_event_manager()

            domain_event = DomainEvent("{event_type}" \
                                       .format(event_type=event_type.upper()),
                                       "{event_type}_{event_detail}" \
                                       .format(event_type=event_type.upper(),
                                               event_detail=event_detail.upper()))
            domain.wait_for_event(domain_event)

        else:
            if type(event_detail) is str:
                port = int(event_detail)
            else:
                port = event_detail
            domain.wait_tcp_socket(port)

    def get_infos(self):
        """
            Returns a dict full of information about the testbed and its
            resources
        """

        infos = {}

        infos['storagepools'] = {}
        for storage_pool in self._storage_pools:
            name = storage_pool.name
            infos['storagepools'][name] = storage_pool.get_infos()

        infos['storagevolumes'] = {}
        for storage_volume in self._storage_volumes:
            name = storage_volume.name
            infos['storagevolumes'][name] = storage_volume.get_infos()

        infos['networks'] = {}
        for network in self._networks:
            name = network.name
            infos['networks'][name] = network.get_infos()

        infos['domains'] = {}
        for domain in self._domains:
            name = domain.name
            infos['domains'][name] = domain.get_infos()

        return infos

    def cleanup(self):
        """Basically destroy everything. After calling this method, the testbed
           comes back at its initial state.
        """
        for domain in self._domains:
            domain.destroy()
        for network in self._networks:
            network.destroy()
        for storage_volume in self._storage_volumes:
            storage_volume.destroy()
        for storage_pool in self._storage_pools:
            storage_pool.destroy()
        for domain in self._domains:
            for template in domain.templates:
                template.delete()

    def xml(self, resource_type, resource_name):
        """Returns the xml representation generated by Cloubed for a resource
           based on the content of the yaml file. This is the actual XML that
           would have been given by Cloubed to Libvirt for creating this
           resource.

           :param string resource_type: the type of the resource (eg. domain,
               network, etc)
           :param string resource_name: the name of the resource in the yaml
               file
           :exceptions CloubedException:
               * the type of resource is not valid
           :exceptions CloubedConfigurationException:
               * the resource name could not be found in yaml file
        """
        if resource_type == "domain":
            domain = self.get_domain_by_name(resource_name)
            return domain.xml()
        elif resource_type == "network":
            network = self.get_network_by_name(resource_name)
            return network.xml()
        elif resource_type == "storagevolume":
            storage_volume = self.get_storage_volume_by_name(resource_name)
            return storage_volume.xml()
        elif resource_type == "storagepool":
            network = self.get_storage_pool_by_name(resource_name)
            return network.xml()
        else:
            raise CloubedException("cannot dump XML of invalid resource type " \
                                   "{type}".format(type=resource_type))

    def clean_exit(self):
        """Cleanly stop the internal HTTP server and the event manager thread
           if they have been launched previously.
        """
        logging.debug("clean exit")
        if self._http_server.launched():
            self._http_server.terminate()
        if self._event_manager is not None:
            self._event_manager.terminate()
Exemple #2
0
    def launch_event_manager(self):

        """ Launch event manager thread unless already done """

        if self._event_manager is None:
            self._event_manager = EventManager(self)