Esempio n. 1
0
def install_chef(cloud, chef_cfg, log):
    # If chef is not installed, we install chef based on 'install_type'
    install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
                                           'packages')
    run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
    if install_type == "gems":
        # This will install and run the chef-client from gems
        chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
        ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
                                               RUBY_VERSION_DEFAULT)
        install_chef_from_gems(cloud.distro, ruby_version, chef_version)
        # Retain backwards compat, by preferring True instead of False
        # when not provided/overriden...
        run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True)
    elif install_type == 'packages':
        # This will install and run the chef-client from packages
        cloud.distro.install_packages(('chef',))
    elif install_type == 'omnibus':
        # This will install as a omnibus unified package
        url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL)
        retries = max(0, util.get_cfg_option_int(chef_cfg,
                                                 "omnibus_url_retries",
                                                 default=OMNIBUS_URL_RETRIES))
        content = url_helper.readurl(url=url, retries=retries)
        with util.tempdir() as tmpd:
            # Use tmpdir over tmpfile to avoid 'text file busy' on execute
            tmpf = "%s/chef-omnibus-install" % tmpd
            util.write_file(tmpf, str(content), mode=0700)
            util.subp([tmpf], capture=False)
    else:
        log.warn("Unknown chef install type '%s'", install_type)
        run = False
    return run
Esempio n. 2
0
def install_chef(cloud, chef_cfg, log):
    # If chef is not installed, we install chef based on 'install_type'
    install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
                                           'packages')
    run = util.get_cfg_option_bool(chef_cfg, 'exec', default=False)
    if install_type == "gems":
        # This will install and run the chef-client from gems
        chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
        ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
                                               RUBY_VERSION_DEFAULT)
        install_chef_from_gems(ruby_version, chef_version, cloud.distro)
        # Retain backwards compat, by preferring True instead of False
        # when not provided/overriden...
        run = util.get_cfg_option_bool(chef_cfg, 'exec', default=True)
    elif install_type == 'packages':
        # This will install and run the chef-client from packages
        cloud.distro.install_packages(('chef', ))
    elif install_type == 'omnibus':
        # This will install as a omnibus unified package
        url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL)
        retries = max(
            0,
            util.get_cfg_option_int(chef_cfg,
                                    "omnibus_url_retries",
                                    default=OMNIBUS_URL_RETRIES))
        content = url_helper.readurl(url=url, retries=retries)
        with util.tempdir() as tmpd:
            # Use tmpdir over tmpfile to avoid 'text file busy' on execute
            tmpf = "%s/chef-omnibus-install" % tmpd
            util.write_file(tmpf, content, mode=0o700)
            util.subp([tmpf], capture=False)
    else:
        log.warn("Unknown chef install type '%s'", install_type)
        run = False
    return run
Esempio n. 3
0
def maybe_perform_dhcp_discovery(nic=None):
    """Perform dhcp discovery if nic valid and dhclient command exists.

    If the nic is invalid or undiscoverable or dhclient command is not found,
    skip dhcp_discovery and return an empty dict.

    @param nic: Name of the network interface we want to run dhclient on.
    @return: A dict of dhcp options from the dhclient discovery if run,
        otherwise an empty dict is returned.
    """
    if nic is None:
        nic = find_fallback_nic()
        if nic is None:
            LOG.debug('Skip dhcp_discovery: Unable to find fallback nic.')
            return {}
    elif nic not in get_devicelist():
        LOG.debug('Skip dhcp_discovery: nic %s not found in get_devicelist.',
                  nic)
        return {}
    dhclient_path = util.which('dhclient')
    if not dhclient_path:
        LOG.debug('Skip dhclient configuration: No dhclient command found.')
        return {}
    with util.tempdir(prefix='cloud-init-dhcp-') as tmpdir:
        return dhcp_discovery(dhclient_path, nic, tmpdir)
Esempio n. 4
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)
Esempio n. 5
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)
Esempio n. 6
0
def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True):
    """
    Mount the device, call method 'callback' passing the directory
    in which it was mounted, then unmount.  Return whatever 'callback'
    returned.  If data != None, also pass data to callback.
    """
    mounted = mounts()
    with util.tempdir() as tmpd:
        umount = False
        devname = "/dev/" + device
        if device in mounted:
            mountpoint = mounted[device]['mountpoint']
        elif devname in mounted:
            mountpoint = mounted[devname]['mountpoint']
        else:
            try:
                mountcmd = ['/usr/sbin/mount']
                mountopts = []
                if rw:
                    mountopts.append('rw')
                else:
                    mountopts.append('ro')
                if sync:
                    # This seems like the safe approach to do
                    # (ie where this is on by default)
                    mountopts.append("sync")
                if mountopts:
                    mountcmd.extend(["-o", ",".join(mountopts)])
                if mtype:
                    mountcmd.extend(['-t', mtype])

                if "/cd" in devname:
                    mountcmd.append('-vcdrfs')
                    mountcmd.append(devname)
                else:
                    mountcmd.append(device)

                mountcmd.append(tmpd)
                util.subp(mountcmd)
                umount = tmpd  # This forces it to be unmounted (when set)
                mountpoint = tmpd
            except (IOError, OSError) as exc:
                raise util.MountFailedError(
                    ("Failed mounting %s to %s due to: %s") %
                    (device, tmpd, exc))
        # Be nice and ensure it ends with a slash
        if not mountpoint.endswith("/"):
            mountpoint += "/"

        with unmounter(umount):
            if data is None:
                ret = callback(mountpoint)
            else:
                ret = callback(mountpoint, data)
            return ret
Esempio n. 7
0
def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True):
    """
    Mount the device, call method 'callback' passing the directory
    in which it was mounted, then unmount.  Return whatever 'callback'
    returned.  If data != None, also pass data to callback.
    """
    mounted = mounts()
    with util.tempdir() as tmpd:
        umount = False
        devname="/dev/" + device
        if device in mounted:
            mountpoint = mounted[device]['mountpoint']
        elif devname in mounted:
            mountpoint = mounted[devname]['mountpoint']
        else:
            try:
                mountcmd = ['/usr/sbin/mount']
                mountopts = []
                if rw:
                    mountopts.append('rw')
                else:
                    mountopts.append('ro')
                if sync:
                    # This seems like the safe approach to do
                    # (ie where this is on by default)
                    mountopts.append("sync")
                if mountopts:
                    mountcmd.extend(["-o", ",".join(mountopts)])
                if mtype:
                    mountcmd.extend(['-t', mtype])

                if "/cd" in devname:
                        mountcmd.append('-vcdrfs')
                        mountcmd.append(devname)
                else:
                        mountcmd.append(device)

                mountcmd.append(tmpd)
                util.subp(mountcmd)
                umount = tmpd  # This forces it to be unmounted (when set)
                mountpoint = tmpd
            except (IOError, OSError) as exc:
                raise util.MountFailedError(("Failed mounting %s to %s due to: %s") % (device, tmpd, exc))
        # Be nice and ensure it ends with a slash
        if not mountpoint.endswith("/"):
            mountpoint += "/"

        with unmounter(umount):
            if data is None:
                ret = callback(mountpoint)
            else:
                ret = callback(mountpoint, data)
            return ret
Esempio n. 8
0
    def test_config_from_klibc_net_cfg(self):
        files = []
        pairs = (('net-eth0.cfg', DHCP_CONTENT_1), ('net-eth1.cfg',
                                                    STATIC_CONTENT_1))

        macs = {'eth1': 'b8:ae:ed:75:ff:2b', 'eth0': 'b8:ae:ed:75:ff:2a'}

        dhcp = copy.deepcopy(DHCP_EXPECTED_1)
        dhcp['mac_address'] = macs['eth0']

        static = copy.deepcopy(STATIC_EXPECTED_1)
        static['mac_address'] = macs['eth1']

        expected = {'version': 1, 'config': [dhcp, static]}
        with util.tempdir() as tmpd:
            for fname, content in pairs:
                fp = os.path.join(tmpd, fname)
                files.append(fp)
                util.write_file(fp, content)

            found = net.config_from_klibc_net_cfg(files=files, mac_addrs=macs)
            self.assertEqual(found, expected)
Esempio n. 9
0
    def test_config_from_klibc_net_cfg(self):
        files = []
        pairs = (('net-eth0.cfg', DHCP_CONTENT_1),
                 ('net-eth1.cfg', STATIC_CONTENT_1))

        macs = {'eth1': 'b8:ae:ed:75:ff:2b',
                'eth0': 'b8:ae:ed:75:ff:2a'}

        dhcp = copy.deepcopy(DHCP_EXPECTED_1)
        dhcp['mac_address'] = macs['eth0']

        static = copy.deepcopy(STATIC_EXPECTED_1)
        static['mac_address'] = macs['eth1']

        expected = {'version': 1, 'config': [dhcp, static]}
        with util.tempdir() as tmpd:
            for fname, content in pairs:
                fp = os.path.join(tmpd, fname)
                files.append(fp)
                util.write_file(fp, content)

            found = net.config_from_klibc_net_cfg(files=files, mac_addrs=macs)
            self.assertEqual(found, expected)
Esempio n. 10
0
def handle(name, cfg, cloud, log, _args):

    # If there isn't a chef key in the configuration don't do anything
    if 'chef' not in cfg:
        log.debug(("Skipping module named %s,"
                  " no 'chef' key in configuration"), name)
        return
    chef_cfg = cfg['chef']

    # Ensure the chef directories we use exist
    for d in CHEF_DIRS:
        util.ensure_dir(d)

    # Set the validation key based on the presence of either 'validation_key'
    # or 'validation_cert'. In the case where both exist, 'validation_key'
    # takes precedence
    for key in ('validation_key', 'validation_cert'):
        if key in chef_cfg and chef_cfg[key]:
            util.write_file('/etc/chef/validation.pem', chef_cfg[key])
            break

    # Create the chef config from template
    template_fn = cloud.get_template_filename('chef_client.rb')
    if template_fn:
        iid = str(cloud.datasource.get_instance_id())
        params = {
            'server_url': chef_cfg['server_url'],
            'node_name': util.get_cfg_option_str(chef_cfg, 'node_name', iid),
            'environment': util.get_cfg_option_str(chef_cfg, 'environment',
                                                   '_default'),
            'validation_name': chef_cfg['validation_name']
        }
        templater.render_to_file(template_fn, '/etc/chef/client.rb', params)
    else:
        log.warn("No template found, not rendering to /etc/chef/client.rb")

    # set the firstboot json
    initial_json = {}
    if 'run_list' in chef_cfg:
        initial_json['run_list'] = chef_cfg['run_list']
    if 'initial_attributes' in chef_cfg:
        initial_attributes = chef_cfg['initial_attributes']
        for k in list(initial_attributes.keys()):
            initial_json[k] = initial_attributes[k]
    util.write_file('/etc/chef/firstboot.json', json.dumps(initial_json))

    # If chef is not installed, we install chef based on 'install_type'
    if (not os.path.isfile('/usr/bin/chef-client') or
            util.get_cfg_option_bool(chef_cfg,
                'force_install', default=False)):

        install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
                                               'packages')
        if install_type == "gems":
            # this will install and run the chef-client from gems
            chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
            ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
                                                   RUBY_VERSION_DEFAULT)
            install_chef_from_gems(cloud.distro, ruby_version, chef_version)
            # and finally, run chef-client
            log.debug('Running chef-client')
            util.subp(['/usr/bin/chef-client',
                       '-d', '-i', '1800', '-s', '20'], capture=False)
        elif install_type == 'packages':
            # this will install and run the chef-client from packages
            cloud.distro.install_packages(('chef',))
        elif install_type == 'omnibus':
            url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL)
            content = url_helper.readurl(url=url, retries=5)
            with util.tempdir() as tmpd:
                # use tmpd over tmpfile to avoid 'Text file busy' on execute
                tmpf = "%s/chef-omnibus-install" % tmpd
                util.write_file(tmpf, str(content), mode=0700)
                util.subp([tmpf], capture=False)
        else:
            log.warn("Unknown chef install type %s", install_type)
def handle(name, cfg, cloud, log, _args):

    # If there isn't a chef key in the configuration don't do anything
    if 'chef' not in cfg:
        log.debug(("Skipping module named %s,"
                   " no 'chef' key in configuration"), name)
        return
    chef_cfg = cfg['chef']

    # Ensure the chef directories we use exist
    for d in CHEF_DIRS:
        util.ensure_dir(d)

    # Set the validation key based on the presence of either 'validation_key'
    # or 'validation_cert'. In the case where both exist, 'validation_key'
    # takes precedence
    for key in ('validation_key', 'validation_cert'):
        if key in chef_cfg and chef_cfg[key]:
            util.write_file('/etc/chef/validation.pem', chef_cfg[key])
            break

    # Create the chef config from template
    template_fn = cloud.get_template_filename('chef_client.rb')
    if template_fn:
        iid = str(cloud.datasource.get_instance_id())
        params = {
            'server_url':
            chef_cfg['server_url'],
            'node_name':
            util.get_cfg_option_str(chef_cfg, 'node_name', iid),
            'environment':
            util.get_cfg_option_str(chef_cfg, 'environment', '_default'),
            'validation_name':
            chef_cfg['validation_name']
        }
        templater.render_to_file(template_fn, '/etc/chef/client.rb', params)
    else:
        log.warn("No template found, not rendering to /etc/chef/client.rb")

    # set the firstboot json
    initial_json = {}
    if 'run_list' in chef_cfg:
        initial_json['run_list'] = chef_cfg['run_list']
    if 'initial_attributes' in chef_cfg:
        initial_attributes = chef_cfg['initial_attributes']
        for k in list(initial_attributes.keys()):
            initial_json[k] = initial_attributes[k]
    util.write_file('/etc/chef/firstboot.json', json.dumps(initial_json))

    # If chef is not installed, we install chef based on 'install_type'
    if (not os.path.isfile('/usr/bin/chef-client') or util.get_cfg_option_bool(
            chef_cfg, 'force_install', default=False)):

        install_type = util.get_cfg_option_str(chef_cfg, 'install_type',
                                               'packages')
        if install_type == "gems":
            # this will install and run the chef-client from gems
            chef_version = util.get_cfg_option_str(chef_cfg, 'version', None)
            ruby_version = util.get_cfg_option_str(chef_cfg, 'ruby_version',
                                                   RUBY_VERSION_DEFAULT)
            install_chef_from_gems(cloud.distro, ruby_version, chef_version)
            # and finally, run chef-client
            log.debug('Running chef-client')
            util.subp(['/usr/bin/chef-client', '-d', '-i', '1800', '-s', '20'],
                      capture=False)
        elif install_type == 'packages':
            # this will install and run the chef-client from packages
            cloud.distro.install_packages(('chef', ))
        elif install_type == 'omnibus':
            url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL)
            content = url_helper.readurl(url=url, retries=5)
            with util.tempdir() as tmpd:
                # use tmpd over tmpfile to avoid 'Text file busy' on execute
                tmpf = "%s/chef-omnibus-install" % tmpd
                util.write_file(tmpf, str(content), mode=0700)
                util.subp([tmpf], capture=False)
        else:
            log.warn("Unknown chef install type %s", install_type)