Пример #1
0
def collect_logs(tarfile, include_userdata):
    """Collect all cloud-init logs and tar them up into the provided tarfile.

    @param tarfile: The path of the tar-gzipped file to create.
    @param include_userdata: Boolean, true means include user-data.
    """
    tarfile = os.path.abspath(tarfile)
    date = datetime.utcnow().date().strftime('%Y-%m-%d')
    log_dir = 'cloud-init-logs-{0}'.format(date)
    with tempdir(dir='/tmp') as tmp_dir:
        log_dir = os.path.join(tmp_dir, log_dir)
        _write_command_output_to_file(
            ['dpkg-query', '--show', "-f=${Version}\n", 'cloud-init'],
            os.path.join(log_dir, 'version'))
        _write_command_output_to_file(['dmesg'],
                                      os.path.join(log_dir, 'dmesg.txt'))
        _write_command_output_to_file(['journalctl', '-o', 'short-precise'],
                                      os.path.join(log_dir, 'journal.txt'))
        for log in CLOUDINIT_LOGS:
            copy(log, log_dir)
        if include_userdata:
            copy(USER_DATA_FILE, log_dir)
        run_dir = os.path.join(log_dir, 'run')
        ensure_dir(run_dir)
        shutil.copytree(CLOUDINIT_RUN_DIR, os.path.join(run_dir, 'cloud-init'))
        with chdir(tmp_dir):
            subp(['tar', 'czvf', tarfile, log_dir.replace(tmp_dir + '/', '')])
Пример #2
0
def dhcp_discovery(dhclient_cmd_path, interface, cleandir):
    """Run dhclient on the interface without scripts or filesystem artifacts.

    @param dhclient_cmd_path: Full path to the dhclient used.
    @param interface: Name of the network inteface on which to dhclient.
    @param cleandir: The directory from which to run dhclient as well as store
        dhcp leases.

    @return: A dict of dhcp options parsed from the dhcp.leases file or empty
        dict.
    """
    LOG.debug('Performing a dhcp discovery on %s', interface)

    # XXX We copy dhclient out of /sbin/dhclient to avoid dealing with strict
    # app armor profiles which disallow running dhclient -sf <our-script-file>.
    # We want to avoid running /sbin/dhclient-script because of side-effects in
    # /etc/resolv.conf any any other vendor specific scripts in
    # /etc/dhcp/dhclient*hooks.d.
    sandbox_dhclient_cmd = os.path.join(cleandir, 'dhclient')
    util.copy(dhclient_cmd_path, sandbox_dhclient_cmd)
    pid_file = os.path.join(cleandir, 'dhclient.pid')
    lease_file = os.path.join(cleandir, 'dhcp.leases')

    # ISC dhclient needs the interface up to send initial discovery packets.
    # Generally dhclient relies on dhclient-script PREINIT action to bring the
    # link up before attempting discovery. Since we are using -sf /bin/true,
    # we need to do that "link up" ourselves first.
    util.subp(['ip', 'link', 'set', 'dev', interface, 'up'], capture=True)
    cmd = [
        sandbox_dhclient_cmd, '-1', '-v', '-lf', lease_file, '-pf', pid_file,
        interface, '-sf', '/bin/true'
    ]
    util.subp(cmd, capture=True)
    return parse_dhcp_lease_file(lease_file)
Пример #3
0
    def apply_locale(self, locale, out_fn=None):
        # Adjust the locals value to the new value
        newconf = StringIO()
        for line in util.load_file(self.login_conf_fn).splitlines():
            newconf.write(
                re.sub(r'^default:', r'default:lang=%s:' % locale, line))
            newconf.write("\n")

        # Make a backup of login.conf.
        util.copy(self.login_conf_fn, self.login_conf_fn_bak)

        # And write the new login.conf.
        util.write_file(self.login_conf_fn, newconf.getvalue())

        try:
            LOG.debug("Running cap_mkdb for %s", locale)
            util.subp(['cap_mkdb', self.login_conf_fn])
        except util.ProcessExecutionError:
            # cap_mkdb failed, so restore the backup.
            util.logexc(LOG, "Failed to apply locale %s", locale)
            try:
                util.copy(self.login_conf_fn_bak, self.login_conf_fn)
            except IOError:
                util.logexc(LOG, "Failed to restore %s backup",
                            self.login_conf_fn)
Пример #4
0
 def execute(self):
     """
     This method executes post-customization script before or after reboot
     based on the presence of rc local.
     """
     self.prepare_script()
     self.install_agent()
     if not self.postreboot:
         LOG.warning("Executing post-customization script inline")
         util.subp(["/bin/sh", self.scriptpath, "postcustomization"])
     else:
         LOG.debug("Scheduling custom script to run post reboot")
         if not os.path.isdir(CustomScriptConstant.POST_CUST_TMP_DIR):
             os.mkdir(CustomScriptConstant.POST_CUST_TMP_DIR)
         # Script "post-customize-guest.sh" and user uploaded script are
         # are present in the same directory and needs to copied to a temp
         # directory to be executed post reboot. User uploaded script is
         # saved as customize.sh in the temp directory.
         # post-customize-guest.sh excutes customize.sh after reboot.
         LOG.debug("Copying post-customization script")
         util.copy(self.scriptpath,
                   CustomScriptConstant.POST_CUST_TMP_DIR + "/customize.sh")
         LOG.debug("Copying script to run post-customization script")
         util.copy(
             os.path.join(self.directory,
                          CustomScriptConstant.POST_CUST_RUN_SCRIPT_NAME),
             CustomScriptConstant.POST_CUST_RUN_SCRIPT)
         LOG.info("Creating post-reboot pending marker")
         util.ensure_file(CustomScriptConstant.POST_REBOOT_PENDING_MARKER)
Пример #5
0
def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone",
                     tz_local="/etc/localtime"):
    util.write_file(tz_conf, str(tz).rstrip() + "\n")
    # This ensures that the correct tz will be used for the system
    if tz_local and tz_file:
        util.copy(tz_file, tz_local)
    return
Пример #6
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     # Adjust the sysconfig clock zone setting
     clock_cfg = {"TIMEZONE": str(tz)}
     rhel_util.update_sysconfig_file(self.clock_conf_fn, clock_cfg)
     # This ensures that the correct tz will be used for the system
     util.copy(tz_file, self.tz_local_fn)
Пример #7
0
def download_extension(extension_url):
    """Downloads an iControl LX RPM package prior to installation processing"""
    if not os.path.isdir(PKG_INSTALL_DIR):
        os.makedirs(PKG_INSTALL_DIR)
    try:
        parsed_url = urlparse.urlparse(extension_url)
        fqdn = parsed_url.netloc
        if wait_for_dns_resolution(fqdn, 120):
            tmp_file_name = '/tmp/download_file.part'
            dest_file = os.path.basename(extension_url)
            if os.path.isfile(tmp_file_name):
                util.del_file(tmp_file_name)
            LOG.debug('GET %s', extension_url)
            resp = requests.get(extension_url, stream=True,
                                allow_redirects=True)
            resp.raise_for_status()
            cont_disp = resp.headers.get('content-disposition')
            if cont_disp:
                cont_disp_fn = re.findall('filename=(.+)', cont_disp)
                if cont_disp_fn > 0:
                    dest_file = cont_disp_fn[0]
            with open(tmp_file_name, 'wb') as out_file:
                for chunk in resp.iter_content(chunk_size=8192):
                    if chunk:
                        out_file.write(chunk)
            if os.path.isfile(tmp_file_name):
                dest_file = PKG_INSTALL_DIR + '/' + dest_file
                util.copy(tmp_file_name, dest_file)
                return True
            LOG.error('could not copy %s to %s', extension_url, dest_file)
        return False
    except Exception as err:
        LOG.error("could not download: %s - %s", extension_url, err)
        return False
Пример #8
0
def config_dhcp(interface, info, create=True):
    infile = "/etc/dhcpcd.ini"
    eat = 0
    updated = 0

    if interface is not None:
        with open(infile, 'r+') as f, util.tempdir() as tmpd:
            tmpf = "%s/dhcpcd.ini" % tmpd
            for line in f.readlines():
                if create is False:
                    util.append_file(tmpf, line)
                else:
                    if eat == 0 and not line.startswith("interface "):
                        util.append_file(tmpf, line)
                    elif eat == 0 and line.startswith("interface "):
                        eat = 1
                    elif eat == 1 and re.match("{", line.strip()):
                        eat = 2
                    elif eat == 2:
                        update_dhcp(tmpf, interface, info)
                        updated = 1
                        eat = 3
            if create is False:
                update_dhcp(tmpf, interface, info)
            else:
                if updated == 0:
                    update_dhcp(tmpf, interface, info)

            util.copy(tmpf, infile)
Пример #9
0
 def execute(self):
     """
     This method executes post-customization script before or after reboot
     based on the presence of rc local.
     """
     self.prepare_script()
     self.install_agent()
     if not self.postreboot:
         LOG.warning("Executing post-customization script inline")
         util.subp(["/bin/sh", self.scriptpath, "postcustomization"])
     else:
         LOG.debug("Scheduling custom script to run post reboot")
         if not os.path.isdir(CustomScriptConstant.POST_CUST_TMP_DIR):
             os.mkdir(CustomScriptConstant.POST_CUST_TMP_DIR)
         # Script "post-customize-guest.sh" and user uploaded script are
         # are present in the same directory and needs to copied to a temp
         # directory to be executed post reboot. User uploaded script is
         # saved as customize.sh in the temp directory.
         # post-customize-guest.sh excutes customize.sh after reboot.
         LOG.debug("Copying post-customization script")
         util.copy(self.scriptpath,
                   CustomScriptConstant.POST_CUST_TMP_DIR + "/customize.sh")
         LOG.debug("Copying script to run post-customization script")
         util.copy(
             os.path.join(self.directory,
                          CustomScriptConstant.POST_CUST_RUN_SCRIPT_NAME),
             CustomScriptConstant.POST_CUST_RUN_SCRIPT)
         LOG.info("Creating post-reboot pending marker")
         util.ensure_file(CustomScriptConstant.POST_REBOOT_PENDING_MARKER)
Пример #10
0
def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone",
                     tz_local="/etc/localtime"):
    util.write_file(tz_conf, str(tz).rstrip() + "\n")
    # This ensures that the correct tz will be used for the system
    if tz_local and tz_file:
        util.copy(tz_file, tz_local)
    return
Пример #11
0
def config_dhcp(interface, info, create=True):
    infile = "/etc/dhcpcd.ini"
    eat = 0
    updated = 0

    if interface is not None:
        with open(infile, 'r+') as f, util.tempdir() as tmpd:
            tmpf = "%s/dhcpcd.ini" % tmpd
            for line in f.readlines():
                if create is False:
                    util.append_file(tmpf, line)
                else:
                    if eat == 0 and not line.startswith("interface "):
                        util.append_file(tmpf, line)
                    elif eat == 0 and line.startswith("interface "):
                        eat = 1
                    elif eat == 1 and re.match("{", line.strip()):
                        eat = 2
                    elif eat == 2:
                        update_dhcp(tmpf, interface, info)
                        updated = 1
                        eat = 3
            if create is False:
                update_dhcp(tmpf, interface, info)
            else:
                if updated == 0:
                    update_dhcp(tmpf, interface, info)

            util.copy(tmpf, infile)
Пример #12
0
    def apply_locale(self, locale, out_fn=None):
        # Adjust the locals value to the new value
        newconf = StringIO()
        for line in util.load_file(self.login_conf_fn).splitlines():
            newconf.write(re.sub(r'^default:',
                                 r'default:lang=%s:' % locale, line))
            newconf.write("\n")

        # Make a backup of login.conf.
        util.copy(self.login_conf_fn, self.login_conf_fn_bak)

        # And write the new login.conf.
        util.write_file(self.login_conf_fn, newconf.getvalue())

        try:
            LOG.debug("Running cap_mkdb for %s", locale)
            util.subp(['cap_mkdb', self.login_conf_fn])
        except util.ProcessExecutionError:
            # cap_mkdb failed, so restore the backup.
            util.logexc(LOG, "Failed to apply locale %s", locale)
            try:
                util.copy(self.login_conf_fn_bak, self.login_conf_fn)
            except IOError:
                util.logexc(LOG, "Failed to restore %s backup",
                            self.login_conf_fn)
Пример #13
0
def configure(
    config,
    server_cfg=SERVER_CFG,
    pubcert_file=PUBCERT_FILE,
    pricert_file=PRICERT_FILE,
):
    # Read server.cfg (if it exists) values from the
    # original file in order to be able to mix the rest up.
    try:
        old_contents = util.load_file(server_cfg, quiet=False, decode=False)
        mcollective_config = ConfigObj(io.BytesIO(old_contents))
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise
        else:
            LOG.debug(
                "Did not find file %s (starting with an empty config)",
                server_cfg,
            )
            mcollective_config = ConfigObj()
    for (cfg_name, cfg) in config.items():
        if cfg_name == "public-cert":
            util.write_file(pubcert_file, cfg, mode=0o644)
            mcollective_config["plugin.ssl_server_public"] = pubcert_file
            mcollective_config["securityprovider"] = "ssl"
        elif cfg_name == "private-cert":
            util.write_file(pricert_file, cfg, mode=0o600)
            mcollective_config["plugin.ssl_server_private"] = pricert_file
            mcollective_config["securityprovider"] = "ssl"
        else:
            if isinstance(cfg, str):
                # Just set it in the 'main' section
                mcollective_config[cfg_name] = cfg
            elif isinstance(cfg, (dict)):
                # Iterate through the config items, create a section if
                # it is needed and then add/or create items as needed
                if cfg_name not in mcollective_config.sections:
                    mcollective_config[cfg_name] = {}
                for (o, v) in cfg.items():
                    mcollective_config[cfg_name][o] = v
            else:
                # Otherwise just try to convert it to a string
                mcollective_config[cfg_name] = str(cfg)

    try:
        # We got all our config as wanted we'll copy
        # the previous server.cfg and overwrite the old with our new one
        util.copy(server_cfg, "%s.old" % (server_cfg))
    except IOError as e:
        if e.errno == errno.ENOENT:
            # Doesn't exist to copy...
            pass
        else:
            raise

    # Now we got the whole (new) file, write to disk...
    contents = io.BytesIO()
    mcollective_config.write(contents)
    util.write_file(server_cfg, contents.getvalue(), mode=0o644)
Пример #14
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     # Adjust the sysconfig clock zone setting
     clock_cfg = {
         'TIMEZONE': str(tz),
     }
     rhel_util.update_sysconfig_file(self.clock_conf_fn, clock_cfg)
     # This ensures that the correct tz will be used for the system
     util.copy(tz_file, self.tz_local_fn)
Пример #15
0
def configure(config, server_cfg=SERVER_CFG,
              pubcert_file=PUBCERT_FILE, pricert_file=PRICERT_FILE):
    # Read server.cfg (if it exists) values from the
    # original file in order to be able to mix the rest up.
    try:
        old_contents = util.load_file(server_cfg, quiet=False, decode=False)
        mcollective_config = ConfigObj(BytesIO(old_contents))
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise
        else:
            LOG.debug("Did not find file %s (starting with an empty"
                      " config)", server_cfg)
            mcollective_config = ConfigObj()
    for (cfg_name, cfg) in config.items():
        if cfg_name == 'public-cert':
            util.write_file(pubcert_file, cfg, mode=0o644)
            mcollective_config[
                'plugin.ssl_server_public'] = pubcert_file
            mcollective_config['securityprovider'] = 'ssl'
        elif cfg_name == 'private-cert':
            util.write_file(pricert_file, cfg, mode=0o600)
            mcollective_config[
                'plugin.ssl_server_private'] = pricert_file
            mcollective_config['securityprovider'] = 'ssl'
        else:
            if isinstance(cfg, six.string_types):
                # Just set it in the 'main' section
                mcollective_config[cfg_name] = cfg
            elif isinstance(cfg, (dict)):
                # Iterate through the config items, create a section if
                # it is needed and then add/or create items as needed
                if cfg_name not in mcollective_config.sections:
                    mcollective_config[cfg_name] = {}
                for (o, v) in cfg.items():
                    mcollective_config[cfg_name][o] = v
            else:
                # Otherwise just try to convert it to a string
                mcollective_config[cfg_name] = str(cfg)

    try:
        # We got all our config as wanted we'll copy
        # the previous server.cfg and overwrite the old with our new one
        util.copy(server_cfg, "%s.old" % (server_cfg))
    except IOError as e:
        if e.errno == errno.ENOENT:
            # Doesn't exist to copy...
            pass
        else:
            raise

    # Now we got the whole (new) file, write to disk...
    contents = BytesIO()
    mcollective_config.write(contents)
    util.write_file(server_cfg, contents.getvalue(), mode=0o644)
Пример #16
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     # Note: "" provides trailing newline during join
     tz_lines = [
         util.make_header(),
         str(tz),
         "",
     ]
     util.write_file(self.tz_conf_fn, "\n".join(tz_lines))
     # This ensures that the correct tz will be used for the system
     util.copy(tz_file, self.tz_local_fn)
Пример #17
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     # Note: "" provides trailing newline during join
     tz_lines = [
         util.make_header(),
         str(tz),
         "",
     ]
     util.write_file(self.tz_conf_fn, "\n".join(tz_lines))
     # This ensures that the correct tz will be used for the system
     util.copy(tz_file, self.tz_local_fn)
Пример #18
0
def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone",
                     tz_local="/etc/localtime"):
    util.write_file(tz_conf, str(tz).rstrip() + "\n")
    # This ensures that the correct tz will be used for the system
    if tz_local and tz_file:
        # use a symlink if there exists a symlink or tz_local is not present
        if os.path.islink(tz_local) or not os.path.exists(tz_local):
            os.symlink(tz_file, tz_local)
        else:
            util.copy(tz_file, tz_local)
    return
Пример #19
0
def dhcp_discovery(dhclient_cmd_path, interface, cleandir):
    """Run dhclient on the interface without scripts or filesystem artifacts.

    @param dhclient_cmd_path: Full path to the dhclient used.
    @param interface: Name of the network inteface on which to dhclient.
    @param cleandir: The directory from which to run dhclient as well as store
        dhcp leases.

    @return: A list of dicts of representing the dhcp leases parsed from the
        dhcp.leases file or empty list.
    """
    LOG.debug('Performing a dhcp discovery on %s', interface)

    # XXX We copy dhclient out of /sbin/dhclient to avoid dealing with strict
    # app armor profiles which disallow running dhclient -sf <our-script-file>.
    # We want to avoid running /sbin/dhclient-script because of side-effects in
    # /etc/resolv.conf any any other vendor specific scripts in
    # /etc/dhcp/dhclient*hooks.d.
    sandbox_dhclient_cmd = os.path.join(cleandir, 'dhclient')
    util.copy(dhclient_cmd_path, sandbox_dhclient_cmd)
    pid_file = os.path.join(cleandir, 'dhclient.pid')
    lease_file = os.path.join(cleandir, 'dhcp.leases')

    # ISC dhclient needs the interface up to send initial discovery packets.
    # Generally dhclient relies on dhclient-script PREINIT action to bring the
    # link up before attempting discovery. Since we are using -sf /bin/true,
    # we need to do that "link up" ourselves first.
    util.subp(['ip', 'link', 'set', 'dev', interface, 'up'], capture=True)
    cmd = [
        sandbox_dhclient_cmd, '-1', '-v', '-lf', lease_file, '-pf', pid_file,
        interface, '-sf', '/bin/true'
    ]
    util.subp(cmd, capture=True)

    # dhclient doesn't write a pid file until after it forks when it gets a
    # proper lease response. Since cleandir is a temp directory that gets
    # removed, we need to wait for that pidfile creation before the
    # cleandir is removed, otherwise we get FileNotFound errors.
    missing = util.wait_for_files([pid_file, lease_file],
                                  maxwait=5,
                                  naplen=0.01)
    if missing:
        LOG.warning("dhclient did not produce expected files: %s",
                    ', '.join(os.path.basename(f) for f in missing))
        return []
    pid_content = util.load_file(pid_file).strip()
    try:
        pid = int(pid_content)
    except ValueError:
        LOG.debug("pid file contains non-integer content '%s'", pid_content)
    else:
        os.kill(pid, signal.SIGKILL)
    return parse_dhcp_lease_file(lease_file)
Пример #20
0
def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone",
                     tz_local="/etc/localtime"):
    util.write_file(tz_conf, str(tz).rstrip() + "\n")
    # This ensures that the correct tz will be used for the system
    if tz_local and tz_file:
        # use a symlink if there exists a symlink or tz_local is not present
        islink = os.path.islink(tz_local)
        if islink or not os.path.exists(tz_local):
            if islink:
                util.del_file(tz_local)
            os.symlink(tz_file, tz_local)
        else:
            util.copy(tz_file, tz_local)
    return
Пример #21
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     if self._dist_uses_systemd():
         # Currently, timedatectl complains if invoked during startup
         # so for compatibility, create the link manually.
         util.del_file(self.tz_local_fn)
         util.sym_link(tz_file, self.tz_local_fn)
     else:
         # Adjust the sysconfig clock zone setting
         clock_cfg = {
             'ZONE': str(tz),
         }
         rhel_util.update_sysconfig_file(self.clock_conf_fn, clock_cfg)
         # This ensures that the correct tz will be used for the system
         util.copy(tz_file, self.tz_local_fn)
Пример #22
0
 def set_timezone(self, tz):
     tz_file = self._find_tz_file(tz)
     if self.uses_systemd():
         # Currently, timedatectl complains if invoked during startup
         # so for compatibility, create the link manually.
         util.del_file(self.tz_local_fn)
         util.sym_link(tz_file, self.tz_local_fn)
     else:
         # Adjust the sysconfig clock zone setting
         clock_cfg = {
             'ZONE': str(tz),
         }
         rhel_util.update_sysconfig_file(self.clock_conf_fn, clock_cfg)
         # This ensures that the correct tz will be used for the system
         util.copy(tz_file, self.tz_local_fn)
Пример #23
0
    def execute(self):
        """
        This method copy the post customize run script to
        cc_scripts_per_instance directory and let this
        module to run post custom script.
        """
        self.prepare_script()

        LOG.debug("Copying post customize run script to %s", self.ccScriptPath)
        util.copy(
            os.path.join(self.directory,
                         CustomScriptConstant.POST_CUSTOM_SCRIPT_NAME),
            self.ccScriptPath)
        st = os.stat(self.ccScriptPath)
        os.chmod(self.ccScriptPath, st.st_mode | stat.S_IEXEC)
        LOG.info("Creating post customization pending marker")
        util.ensure_file(CustomScriptConstant.POST_CUSTOM_PENDING_MARKER)
Пример #24
0
    def prepare_script(self):
        if not os.path.exists(self.scriptpath):
            raise CustomScriptNotFound(
                "Script %s not found!! Cannot execute custom script!" %
                self.scriptpath)

        util.ensure_dir(CustomScriptConstant.CUSTOM_TMP_DIR)

        LOG.debug("Copying custom script to %s",
                  CustomScriptConstant.CUSTOM_SCRIPT)
        util.copy(self.scriptpath, CustomScriptConstant.CUSTOM_SCRIPT)

        # Strip any CR characters from the decoded script
        content = util.load_file(CustomScriptConstant.CUSTOM_SCRIPT).replace(
            "\r", "")
        util.write_file(CustomScriptConstant.CUSTOM_SCRIPT,
                        content,
                        mode=0o544)
Пример #25
0
def make_dhcp4_request(interface, timeout=120):
    """Makes DHCPv4 queries out a linux link device"""
    dhcp_lease_dir_exists()
    tmp_conf_file = DHCP_LEASE_DIR + '/dhclient.conf'
    lease_file = DHCP_LEASE_DIR + '/' + interface + '.lease'
    tmp_lease_file = '/tmp/' + interface + '.lease'
    fnull = open(os.devnull, 'w')
    dhclient_cf = open(tmp_conf_file, 'w')
    dhclient_cf.write(
        "\nrequest subnet-mask, broadcast-address, time-offset, routers,\n")
    dhclient_cf.write(
        "        domain-name, domain-name-servers, domain-search, host-name,\n")
    dhclient_cf.write(
        "        root-path, interface-mtu, classless-static-routes;\n")
    dhclient_cf.close()
    if os.path.isfile(lease_file):
        util.del_file(lease_file)
    subprocess.call(['/bin/pkill', 'dhclient'], stdout=fnull)
    subprocess.call(['/sbin/ip', 'link', 'set', interface, 'up'], stdout=fnull)
    subprocess.call(['/sbin/dhclient',
                     '-lf',
                     tmp_lease_file,
                     '-cf',
                     tmp_conf_file,
                     '-1',
                     '-timeout',
                     str(timeout),
                     '-pf',
                     '/tmp/dhclient.' + interface + '.pid',
                     '-sf',
                     '/bin/echo',
                     interface], stdout=fnull)
    if os.path.getsize(tmp_lease_file) > 0:
        util.copy(tmp_lease_file, lease_file)
        subprocess.call(['/bin/pkill', 'dhclient'], stdout=fnull)
        util.del_file('/tmp/dhclient.' + interface + '.pid')
        util.del_file(tmp_lease_file)
        return True
    else:
        subprocess.call(['/bin/pkill', 'dhclient'], stdout=fnull)
        util.del_file('/tmp/dhclient.' + interface + '.pid')
        util.del_file(tmp_lease_file)
    return False
Пример #26
0
def _collect_file(path, out_dir, verbosity):
    if os.path.isfile(path):
        copy(path, out_dir)
        _debug("collected file: %s\n" % path, 1, verbosity)
    else:
        _debug("file %s did not exist\n" % path, 2, verbosity)
Пример #27
0
def dhcp_discovery(dhclient_cmd_path, interface, cleandir):
    """Run dhclient on the interface without scripts or filesystem artifacts.

    @param dhclient_cmd_path: Full path to the dhclient used.
    @param interface: Name of the network inteface on which to dhclient.
    @param cleandir: The directory from which to run dhclient as well as store
        dhcp leases.

    @return: A list of dicts of representing the dhcp leases parsed from the
        dhcp.leases file or empty list.
    """
    LOG.debug('Performing a dhcp discovery on %s', interface)

    # XXX We copy dhclient out of /sbin/dhclient to avoid dealing with strict
    # app armor profiles which disallow running dhclient -sf <our-script-file>.
    # We want to avoid running /sbin/dhclient-script because of side-effects in
    # /etc/resolv.conf any any other vendor specific scripts in
    # /etc/dhcp/dhclient*hooks.d.
    sandbox_dhclient_cmd = os.path.join(cleandir, 'dhclient')
    util.copy(dhclient_cmd_path, sandbox_dhclient_cmd)
    pid_file = os.path.join(cleandir, 'dhclient.pid')
    lease_file = os.path.join(cleandir, 'dhcp.leases')

    # ISC dhclient needs the interface up to send initial discovery packets.
    # Generally dhclient relies on dhclient-script PREINIT action to bring the
    # link up before attempting discovery. Since we are using -sf /bin/true,
    # we need to do that "link up" ourselves first.
    util.subp(['ip', 'link', 'set', 'dev', interface, 'up'], capture=True)
    cmd = [sandbox_dhclient_cmd, '-1', '-v', '-lf', lease_file,
           '-pf', pid_file, interface, '-sf', '/bin/true']
    util.subp(cmd, capture=True)

    # Wait for pid file and lease file to appear, and for the process
    # named by the pid file to daemonize (have pid 1 as its parent). If we
    # try to read the lease file before daemonization happens, we might try
    # to read it before the dhclient has actually written it. We also have
    # to wait until the dhclient has become a daemon so we can be sure to
    # kill the correct process, thus freeing cleandir to be deleted back
    # up the callstack.
    missing = util.wait_for_files(
        [pid_file, lease_file], maxwait=5, naplen=0.01)
    if missing:
        LOG.warning("dhclient did not produce expected files: %s",
                    ', '.join(os.path.basename(f) for f in missing))
        return []

    ppid = 'unknown'
    for _ in range(0, 1000):
        pid_content = util.load_file(pid_file).strip()
        try:
            pid = int(pid_content)
        except ValueError:
            pass
        else:
            ppid = util.get_proc_ppid(pid)
            if ppid == 1:
                LOG.debug('killing dhclient with pid=%s', pid)
                os.kill(pid, signal.SIGKILL)
                return parse_dhcp_lease_file(lease_file)
        time.sleep(0.01)

    LOG.error(
        'dhclient(pid=%s, parentpid=%s) failed to daemonize after %s seconds',
        pid_content, ppid, 0.01 * 1000
    )
    return parse_dhcp_lease_file(lease_file)
Пример #28
0
def dhcp_discovery(dhclient_cmd_path, interface, cleandir, dhcp_log_func=None):
    """Run dhclient on the interface without scripts or filesystem artifacts.

    @param dhclient_cmd_path: Full path to the dhclient used.
    @param interface: Name of the network inteface on which to dhclient.
    @param cleandir: The directory from which to run dhclient as well as store
        dhcp leases.
    @param dhcp_log_func: A callable accepting the dhclient output and error
        streams.

    @return: A list of dicts of representing the dhcp leases parsed from the
        dhcp.leases file or empty list.
    """
    LOG.debug("Performing a dhcp discovery on %s", interface)

    # XXX We copy dhclient out of /sbin/dhclient to avoid dealing with strict
    # app armor profiles which disallow running dhclient -sf <our-script-file>.
    # We want to avoid running /sbin/dhclient-script because of side-effects in
    # /etc/resolv.conf any any other vendor specific scripts in
    # /etc/dhcp/dhclient*hooks.d.
    sandbox_dhclient_cmd = os.path.join(cleandir, "dhclient")
    util.copy(dhclient_cmd_path, sandbox_dhclient_cmd)
    pid_file = os.path.join(cleandir, "dhclient.pid")
    lease_file = os.path.join(cleandir, "dhcp.leases")

    # In some cases files in /var/tmp may not be executable, launching dhclient
    # from there will certainly raise 'Permission denied' error. Try launching
    # the original dhclient instead.
    if not os.access(sandbox_dhclient_cmd, os.X_OK):
        sandbox_dhclient_cmd = dhclient_cmd_path

    # ISC dhclient needs the interface up to send initial discovery packets.
    # Generally dhclient relies on dhclient-script PREINIT action to bring the
    # link up before attempting discovery. Since we are using -sf /bin/true,
    # we need to do that "link up" ourselves first.
    subp.subp(["ip", "link", "set", "dev", interface, "up"], capture=True)
    cmd = [
        sandbox_dhclient_cmd,
        "-1",
        "-v",
        "-lf",
        lease_file,
        "-pf",
        pid_file,
        interface,
        "-sf",
        "/bin/true",
    ]
    out, err = subp.subp(cmd, capture=True)

    # Wait for pid file and lease file to appear, and for the process
    # named by the pid file to daemonize (have pid 1 as its parent). If we
    # try to read the lease file before daemonization happens, we might try
    # to read it before the dhclient has actually written it. We also have
    # to wait until the dhclient has become a daemon so we can be sure to
    # kill the correct process, thus freeing cleandir to be deleted back
    # up the callstack.
    missing = util.wait_for_files([pid_file, lease_file],
                                  maxwait=5,
                                  naplen=0.01)
    if missing:
        LOG.warning(
            "dhclient did not produce expected files: %s",
            ", ".join(os.path.basename(f) for f in missing),
        )
        return []

    ppid = "unknown"
    daemonized = False
    for _ in range(0, 1000):
        pid_content = util.load_file(pid_file).strip()
        try:
            pid = int(pid_content)
        except ValueError:
            pass
        else:
            ppid = util.get_proc_ppid(pid)
            if ppid == 1:
                LOG.debug("killing dhclient with pid=%s", pid)
                os.kill(pid, signal.SIGKILL)
                daemonized = True
                break
        time.sleep(0.01)

    if not daemonized:
        LOG.error(
            "dhclient(pid=%s, parentpid=%s) failed to daemonize after %s "
            "seconds",
            pid_content,
            ppid,
            0.01 * 1000,
        )
    if dhcp_log_func is not None:
        dhcp_log_func(out, err)
    return parse_dhcp_lease_file(lease_file)
Пример #29
0
def _collect_file(path, out_dir, verbosity):
    if os.path.isfile(path):
        copy(path, out_dir)
        _debug("collected file: %s\n" % path, 1, verbosity)
    else:
        _debug("file %s did not exist\n" % path, 2, verbosity)
Пример #30
0
def dhcp_discovery(dhclient_cmd_path, interface, cleandir):
    """Run dhclient on the interface without scripts or filesystem artifacts.

    @param dhclient_cmd_path: Full path to the dhclient used.
    @param interface: Name of the network inteface on which to dhclient.
    @param cleandir: The directory from which to run dhclient as well as store
        dhcp leases.

    @return: A list of dicts of representing the dhcp leases parsed from the
        dhcp.leases file or empty list.
    """
    LOG.debug('Performing a dhcp discovery on %s', interface)

    # XXX We copy dhclient out of /sbin/dhclient to avoid dealing with strict
    # app armor profiles which disallow running dhclient -sf <our-script-file>.
    # We want to avoid running /sbin/dhclient-script because of side-effects in
    # /etc/resolv.conf any any other vendor specific scripts in
    # /etc/dhcp/dhclient*hooks.d.
    sandbox_dhclient_cmd = os.path.join(cleandir, 'dhclient')
    util.copy(dhclient_cmd_path, sandbox_dhclient_cmd)
    pid_file = os.path.join(cleandir, 'dhclient.pid')
    lease_file = os.path.join(cleandir, 'dhcp.leases')

    # ISC dhclient needs the interface up to send initial discovery packets.
    # Generally dhclient relies on dhclient-script PREINIT action to bring the
    # link up before attempting discovery. Since we are using -sf /bin/true,
    # we need to do that "link up" ourselves first.
    util.subp(['ip', 'link', 'set', 'dev', interface, 'up'], capture=True)
    cmd = [sandbox_dhclient_cmd, '-1', '-v', '-lf', lease_file,
           '-pf', pid_file, interface, '-sf', '/bin/true']
    util.subp(cmd, capture=True)

    # Wait for pid file and lease file to appear, and for the process
    # named by the pid file to daemonize (have pid 1 as its parent). If we
    # try to read the lease file before daemonization happens, we might try
    # to read it before the dhclient has actually written it. We also have
    # to wait until the dhclient has become a daemon so we can be sure to
    # kill the correct process, thus freeing cleandir to be deleted back
    # up the callstack.
    missing = util.wait_for_files(
        [pid_file, lease_file], maxwait=5, naplen=0.01)
    if missing:
        LOG.warning("dhclient did not produce expected files: %s",
                    ', '.join(os.path.basename(f) for f in missing))
        return []

    ppid = 'unknown'
    for _ in range(0, 1000):
        pid_content = util.load_file(pid_file).strip()
        try:
            pid = int(pid_content)
        except ValueError:
            pass
        else:
            ppid = util.get_proc_ppid(pid)
            if ppid == 1:
                LOG.debug('killing dhclient with pid=%s', pid)
                os.kill(pid, signal.SIGKILL)
                return parse_dhcp_lease_file(lease_file)
        time.sleep(0.01)

    LOG.error(
        'dhclient(pid=%s, parentpid=%s) failed to daemonize after %s seconds',
        pid_content, ppid, 0.01 * 1000
    )
    return parse_dhcp_lease_file(lease_file)