Beispiel #1
0
    def _get_mapped_slave(self, tm_id):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]

        libvirt_domain = None
        if "libvirt_domain" in pm["params"]:
            libvirt_domain = pm["params"]["libvirt_domain"]

        machine = Machine(tm_id, hostname, libvirt_domain)

        used = []
        if_map = self._map["machines"][tm_id]["interfaces"]
        for t_if, p_if in if_map.iteritems():
            used.append(p_if)
            if_data = pm["interfaces"][p_if]

            for t_net, p_net in self._map["networks"].iteritems():
                if pm["interfaces"][p_if]["network"] == p_net:
                    break

            iface = machine.new_static_interface(t_if, "eth")
            iface.set_hwaddr(if_data["hwaddr"])
            iface.set_network(t_net)

        for if_id, if_data in pm["interfaces"].iteritems():
            if if_id not in used:
                iface = machine.new_unused_interface("eth")
                iface.set_hwaddr(if_data["hwaddr"])
                iface.set_network(t_net)

        return machine
Beispiel #2
0
    def _prepare_virtual_slave(self, tm_id, tm):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]
        libvirt_domain = pm["params"]["libvirt_domain"]

        rpcport = None
        if "rpc_port" in pm["params"]:
            rpcport = pm["params"]["rpc_port"]

        machine = Machine(tm_id, hostname, libvirt_domain, rpcport)

        # make all the existing unused
        for if_id, if_data in pm["interfaces"].iteritems():
            iface = machine.new_unused_interface("eth")
            iface.set_hwaddr(if_data["params"]["hwaddr"])
            iface.set_network(None)

        # add all the other devices
        for if_id, if_data in tm["interfaces"].iteritems():
            iface = machine.new_virtual_interface(if_id, "eth")
            iface.set_network(if_data["network"])
            if "hwaddr" in if_data["params"]:
                iface.set_hwaddr(if_data["params"]["hwaddr"])
            if "driver" in if_data["params"]:
                iface.set_driver(if_data["params"]["driver"])

        return machine
Beispiel #3
0
    def connect_host(self, hostname, timeout=60, port=None, machine_id=None,
                     security=None):
        ctl_config = self._controller._config
        msg_dispatcher = self._controller._msg_dispatcher

        if security is None:
            security = {"auth_type": "none"}

        if machine_id is None:
            machine_id = hostname

        m = Machine(machine_id, hostname, msg_dispatcher,
                    ctl_config, None, port, security)

        def condition():
            try:
                m.init_connection(timeout=1)
                return True
            except:
                log_exc_traceback()
                return False

        msg_dispatcher.wait_for_condition(condition, timeout)

        host = Host(m)
        self._controller._prepare_machine(m)
        m.start_recipe(self._recipe)
        return host
Beispiel #4
0
    def _prepare_virtual_slave(self, tm_id, tm):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]
        libvirt_domain = pm["params"]["libvirt_domain"]

        rpcport = None
        if "rpc_port" in pm["params"]:
            rpcport = pm["params"]["rpc_port"]

        machine = Machine(tm_id, hostname, libvirt_domain, rpcport,
                          pm["security"])

        # make all the existing unused
        for if_id, if_data in pm["interfaces"].iteritems():
            iface = machine.new_unused_interface("eth")
            iface.set_hwaddr(if_data["params"]["hwaddr"])
            iface.set_network(None)

        # add all the other devices
        for if_id, if_data in tm["interfaces"].iteritems():
            iface = machine.new_virtual_interface(if_id, "eth")
            iface.set_network(if_data["network"])
            if "hwaddr" in if_data["params"]:
                iface.set_hwaddr(if_data["params"]["hwaddr"])
            if "driver" in if_data["params"]:
                iface.set_driver(if_data["params"]["driver"])

        return machine
Beispiel #5
0
    def _get_mapped_slave(self, tm_id):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]

        rpcport = None
        if "rpc_port" in pm["params"]:
            rpcport = pm["params"]["rpc_port"]

        machine = Machine(tm_id, hostname, None, rpcport)

        used = []
        if_map = self._map["machines"][tm_id]["interfaces"]
        for t_if, p_if in if_map.iteritems():
            pool_id = p_if["target"]
            used.append(pool_id)
            if_data = pm["interfaces"][pool_id]

            iface = machine.new_static_interface(t_if, "eth")
            iface.set_hwaddr(if_data["params"]["hwaddr"])

            for t_net, p_net in self._map["networks"].iteritems():
                if pm["interfaces"][pool_id]["network"] == p_net:
                    iface.set_network(t_net)
                    break

        for if_id, if_data in pm["interfaces"].iteritems():
            if if_id not in used:
                iface = machine.new_unused_interface("eth")
                iface.set_hwaddr(if_data["params"]["hwaddr"])
                iface.set_network(None)

        return machine
Beispiel #6
0
    def _get_mapped_slave(self, tm_id):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]

        libvirt_domain = None
        if "libvirt_domain" in pm["params"]:
            libvirt_domain = pm["params"]["libvirt_domain"]

        machine = Machine(tm_id, hostname, libvirt_domain)

        used = []
        if_map = self._map["machines"][tm_id]["interfaces"]
        for t_if, p_if in if_map.iteritems():
            used.append(p_if)
            if_data = pm["interfaces"][p_if]

            for t_net, p_net in self._map["networks"].iteritems():
                if pm["interfaces"][p_if]["network"] == p_net:
                    break

            iface = machine.new_static_interface(t_if, "eth")
            iface.set_hwaddr(if_data["hwaddr"])
            iface.set_network(t_net)

        for if_id, if_data in pm["interfaces"].iteritems():
            if if_id not in used:
                iface = machine.new_unused_interface("eth")
                iface.set_hwaddr(if_data["hwaddr"])
                iface.set_network(t_net)

        return machine
Beispiel #7
0
    def _get_mapped_slave(self, tm_id):
        pm_id = self._get_machine_mapping(tm_id)
        pm = self._pool[pm_id]

        hostname = pm["params"]["hostname"]

        rpcport = None
        if "rpc_port" in pm["params"]:
            rpcport = pm["params"]["rpc_port"]

        machine = Machine(tm_id, hostname, None, rpcport, pm["security"])

        used = []
        if_map = self._map["machines"][tm_id]["interfaces"]
        for t_if, p_if in if_map.iteritems():
            pool_id = p_if["target"]
            used.append(pool_id)
            if_data = pm["interfaces"][pool_id]

            iface = machine.new_static_interface(t_if, "eth")
            iface.set_hwaddr(if_data["params"]["hwaddr"])

            for t_net, p_net in self._map["networks"].iteritems():
                if pm["interfaces"][pool_id]["network"] == p_net:
                    iface.set_network(t_net)
                    break

        for if_id, if_data in pm["interfaces"].iteritems():
            if if_id not in used:
                iface = machine.new_unused_interface("eth")
                iface.set_hwaddr(if_data["params"]["hwaddr"])
                iface.set_network(None)

        return machine
Beispiel #8
0
    def _check_machine(self, machine: Machine):
        """Method checks if the agent process inside of the container is running."""
        hostname = machine.get_hostname()
        logging.debug(f"Checking connection with machine {hostname}")
        connection = socket.socket()
        connection.settimeout(self._start_timeout)

        retry_counter = 5

        for i in range(retry_counter):
            logging.debug(
                f"Connecting to {machine.get_hostname()}, retry counter: {i}")
            try:
                connection.connect((hostname, machine._port))
            except (ConnectionRefusedError, ConnectionAbortedError):
                sleep(1)
                continue

            logging.debug(f"Connected to agent process at machine {hostname}")
            break  # successfully connected
        else:
            raise PoolManagerError(f"Could not connect to machine {hostname}")

        err = connection.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
        if err:
            connection.close()
            raise PoolManagerError(f"Could not connect to machine {hostname}")

        connection.shutdown(socket.SHUT_RDWR)
        connection.close()

        logging.info(f"Agent process is running at {hostname}")
Beispiel #9
0
    def _create_container(self, name: str, reqs: dict):
        logging.info("Creating container " + name)

        if "rpc_port" in reqs:
            rpc_port = reqs["rpc_port"]
        else:
            rpc_port = None

        self._pool[name] = {
            "interfaces": {},
            "params": {
                "hostname": "",
                "rpc_port": rpc_port
            },
            "security": {
                "auth_type": "none"
            },
            "available": True,
        }

        try:
            container = self._podman_client.containers.create(self.image,
                                                              hostname=name,
                                                              privileged=True)
        except APIError as e:
            raise PoolManagerError(f"Could not create container {name}: {e}")

        machine = Machine(
            name,
            "",
            self._msg_dispatcher,
            self._ctl_config,
            None,
            rpc_port,
            self._pool[name]["security"],
            reqs,
        )  # to get hostname the container needs to run

        self._start_container(container, machine)
        if self._pool_check:
            self._check_machine(
                machine)  # checks if the agent process is already running

        self._pool[name]["params"]["hostname"] = machine.get_hostname()

        return container, machine
Beispiel #10
0
    def _start_container(container: Container, machine: Machine):
        logging.debug("Starting container " + container.name)
        container.start()

        container.reload()
        container.wait(condition="running")
        machine._hostname = container.attrs["NetworkSettings"]["Networks"][
            "podman"]["IPAddress"]
Beispiel #11
0
 def _connect_and_configure_machine(self, hostname, port):
     """
     Connects to Slave and configures it
     """
     try:
         self._machine = Machine(1, hostname, None, port)
         self._machine.set_rpc(self._msg_dispatcher)
         self._machine.configure("MachinePoolWizard")
         return True
     except:
         sys.stderr.write("Remote machine '%s:%s' configuration failed!\n"
                           % (hostname, port))
         self._msg_dispatcher.disconnect_slave(1)
         return False
Beispiel #12
0
    def __init__(self, pools, msg_dispatcher, ctl_config, pool_checks=True):
        self._map = {}
        self._pools = {}
        self._pool = {}
        self._msg_dispatcher = msg_dispatcher
        self._ctl_config = ctl_config

        self._allow_virt = ctl_config.get_option("environment",
                                                 "allow_virtual")
        self._allow_virt &= check_process_running("libvirtd")
        self._pool_checks = pool_checks

        logging.info("Checking machine pool availability.")
        for pool_name, pool_dir in list(pools.items()):
            self._pools[pool_name] = {}
            self.add_dir(pool_name, pool_dir)
            if len(self._pools[pool_name]) == 0:
                del self._pools[pool_name]

        self._machines = {}
        for pool_name, machines in list(self._pools.items()):
            pool = self._machines[pool_name] = {}
            for m_id, m_spec in list(machines.items()):
                params = m_spec["params"]

                hostname = params["hostname"]

                if "libvirt_domain" in params:
                    libvirt_domain = params["libvirt_domain"]
                else:
                    libvirt_domain = None

                if "rpc_port" in params:
                    rpc_port = params["rpc_port"]
                else:
                    rpc_port = None

                pool[m_id] = Machine(m_id, hostname, self._msg_dispatcher,
                                     ctl_config, libvirt_domain, rpc_port,
                                     m_spec["security"], params)
                pool[m_id].init_connection()
                #TODO check if all described devices are available

        logging.info("Finished loading pools.")
Beispiel #13
0
class Wizard:
    def __init__(self):
        self._msg_dispatcher = MessageDispatcherLite()
        self._pool_dir = os.path.expanduser("~/.lnst/pool")

    def interactive(self):
        """
        Starts Wizard in interactive mode. Wizard requests hostname and port
        from user, tests connectivity to entered host, then he tries to connect
        and configure slave on host machine, and finally he requests list of
        ethernet interfaces in state DOWN. Then he writes them into .xml file
        named by user. User can choose which interfaces should be added to the
        .xml file.
        """

        pool_dir = raw_input("Enter path to pool directory "\
                             "(default: ~/.lnst/pool): ")
        if pool_dir != "":
            self._pool_dir = os.path.expanduser(pool_dir)
            print "Pool directory set to %s" % self._pool_dir

        while True:
            while True:
                hostname = raw_input("Enter hostname: ")
                try:
                # Tests if hostname is translatable into IP address
                    socket.gethostbyname(hostname)
                    break
                except:
                    sys.stderr.write("Hostname is not translatable into valid"\
                                     " IP address.\n")
                    continue
            while True:
                port = raw_input("Enter port(default: 9999): ")
                if port == "":
                    port = DefaultRPCPort
                try:
                    port = int(port)
                    break
                except:
                    sys.stderr.write("Invalid port.")
                    continue
            msg = self._get_suitable_interfaces(socket.gethostbyname(hostname),\
                                             port)
            if msg:
                self._write_to_xml(msg, hostname, port, "interactive")
            next_machine = raw_input("Do you want to add another machine? "\
                                     "[Y/n]: ")
            if next_machine.lower() == 'y' or next_machine == "":
                continue
            else:
                break
            return

    def noninteractive(self, hostlist):
        """
        Starts Wizard in noninteractive mode. Wizard gets list of hosts and
        ports as arguments. He tries to connect and get info about suitable
        interfaces for each of the hosts. Noninteractive mode does not prompt
        user about anything, it automatically adds all suitable interfaces into
        .xml file named the same as the hostname of the selected machine.
        """
        self._mode = "noninteractive"

        for host in hostlist:
            # Checks if port was entered along with hostname
            if host.find(":") != -1:
               hostname = host.split(':')[0]
               try:
                   port = int(host.split(':')[1])
               except:
                   port = DefaultRPCPort
            else:
                hostname = host
                port = DefaultRPCPort
            msg = self._get_suitable_interfaces(hostname, port)
            if not msg:
                continue
            self._write_to_xml(msg, hostname, port, "noninteractive")

    def _get_suitable_interfaces(self, hostname, port):
        """
        Calls all functions, which are used by both interactive and
        noninteractive mode to get list of suitable interfaces. The list is
        saved to variable msg.
        """
        if not test_tcp_connection(hostname, port):
            sys.stderr.write("Host destination '%s:%s' unreachable.\n"
                              % (hostname, port))
            return False
        if not self._connect_and_configure_machine(hostname, port):
            return False
        msg =  self._get_device_ifcs(hostname, port)
        self._msg_dispatcher.disconnect_slave(1)
        return msg

    def _get_device_ifcs(self, hostname, port):
        """
        Sends RPC call request to Slave to call function get_devices, which
        returns list of ethernet devices which are in state DOWN.
        """
        msg = self._machine._rpc_call("get_devices")
        if msg == {}:
            sys.stderr.write("No suitable interfaces found on the slave "\
                             "'%s:%s'.\n" % (hostname, port))
            return False
        return msg

    def _connect_and_configure_machine(self, hostname, port):
        """
        Connects to Slave and configures it
        """
        try:
            self._machine = Machine(1, hostname, None, port)
            self._machine.set_rpc(self._msg_dispatcher)
            self._machine.configure("MachinePoolWizard")
            return True
        except:
            sys.stderr.write("Remote machine '%s:%s' configuration failed!\n"
                              % (hostname, port))
            self._msg_dispatcher.disconnect_slave(1)
            return False

    def _write_to_xml(self, msg, hostname, port, mode):
        """
        Used for writing desired output into .xml file. In interactive mode,
        user is prompted for every interface, in noninteractive mode all
        interfaces are automatically added to the .xml file.
        """
        if mode == "interactive":
            output_file = raw_input("Enter the name of the output .xml file "\
                                    "(without .xml, default is hostname.xml): ")
        if mode == "noninteractive" or output_file == "":
            output_file = hostname

        impl = getDOMImplementation()
        doc = impl.createDocument(None, "slavemachine", None)
        top_el = doc.documentElement
        params_el = doc.createElement("params")
        top_el.appendChild(params_el)
        param_el = doc.createElement("param")
        param_el.setAttribute("name", "hostname")
        param_el.setAttribute("value", hostname)
        params_el.appendChild(param_el)
        interfaces_el = doc.createElement("interfaces")
        top_el.appendChild(interfaces_el)

        devices_added = 0
        for interface in msg.itervalues():
            if mode == 'interactive':
                answer = raw_input("Do you want to add interface '%s' (%s) "
                                   "to the recipe? [Y/n]" % (interface['name'],
                                                          interface['hwaddr']))
            if mode == "noninteractive" or answer.lower() == 'y'\
               or answer == "":
                devices_added += 1
                eth_el = doc.createElement("eth")
                eth_el.setAttribute("id", interface['name'])
                eth_el.setAttribute("label", "default_network")
                interfaces_el.appendChild(eth_el)
                params_el = doc.createElement("params")
                eth_el.appendChild(params_el)
                param_el = doc.createElement("param")
                param_el.setAttribute("name", "hwaddr")
                param_el.setAttribute("value", interface['hwaddr'])
                params_el.appendChild(param_el)
        if devices_added == 0:
            sys.stderr.write("You didn't add any interface, no file '%s.xml' "\
                  "will be created!\n" % output_file)
            return

        mkdir_p(self._pool_dir)

        try:
            f = open(self._pool_dir + "/" + output_file + ".xml", 'w')
            f.write(doc.toprettyxml())
            f.close()
        except:
            sys.stderr.write("File '%s.xml' could not be opened "\
                             "or data written." % output_file+"\n")
            raise WizardException()

        print "File '%s.xml' successfuly created." % output_file