예제 #1
0
파일: hv_xen.py 프로젝트: badp/ganeti
  def _WriteNICInfoFile(cls, instance, idx, nic):
    """Write the Xen config file for the instance.

    This version of the function just writes the config file from static data.

    """
    instance_name = instance.name
    dirs = [(dname, constants.RUN_DIRS_MODE)
            for dname in cls._DIRS + [cls._InstanceNICDir(instance_name)]]
    utils.EnsureDirs(dirs)

    cfg_file = cls._InstanceNICFile(instance_name, idx)
    data = StringIO()

    data.write("TAGS=%s\n" % r"\ ".join(instance.GetTags()))
    if nic.netinfo:
      netinfo = objects.Network.FromDict(nic.netinfo)
      for k, v in netinfo.HooksDict().iteritems():
        data.write("%s=%s\n" % (k, v))

    data.write("MAC=%s\n" % nic.mac)
    if nic.ip:
      data.write("IP=%s\n" % nic.ip)
    data.write("INTERFACE_INDEX=%s\n" % str(idx))
    if nic.name:
      data.write("INTERFACE_NAME=%s\n" % nic.name)
    data.write("INTERFACE_UUID=%s\n" % nic.uuid)
    data.write("MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
    data.write("LINK=%s\n" % nic.nicparams[constants.NIC_LINK])

    try:
      utils.WriteFile(cfg_file, data=data.getvalue())
    except EnvironmentError, err:
      raise errors.HypervisorError("Cannot write Xen instance configuration"
                                   " file %s: %s" % (cfg_file, err))
예제 #2
0
 def testEnsureDirs(self):
     utils.EnsureDirs([
         (utils.PathJoin(self.dir, "foo"), 0o777),
         (utils.PathJoin(self.dir, "bar"), 0000),
     ])
     self.assertEquals(
         os.stat(utils.PathJoin(self.dir, "foo"))[0] & 0o777, 0o777)
     self.assertEquals(
         os.stat(utils.PathJoin(self.dir, "bar"))[0] & 0o777, 0000)
예제 #3
0
    def _EnsureDirectoryExistence(self):
        """Ensures all the directories needed for LXC use exist.

    """
        utils.EnsureDirs([
            (self._ROOT_DIR, self._DIR_MODE),
            (self._LOG_DIR, 0o750),
            (self._INSTANCE_DIR, 0o750),
        ])
예제 #4
0
    def StartInstance(self, instance, block_devices, startup_paused):
        """Start an instance.

    For LXC, we try to mount the block device and execute 'lxc-start'.
    We use volatile containers.

    """
        LXCHypervisor._VerifyDiskRequirements(block_devices)

        stash = {}

        # Since LXC version >= 1.0.0, the LXC strictly requires all cgroup
        # subsystems mounted before starting a container.
        # Try to mount all cgroup subsystems needed to start a LXC container.
        self._EnsureCgroupMounts(instance.hvparams)

        root_dir = self._InstanceDir(instance.name)
        try:
            utils.EnsureDirs([(root_dir, self._DIR_MODE)])
        except errors.GenericError as err:
            raise HypervisorError("Creating instance directory failed: %s",
                                  str(err))

        log_file = self._InstanceLogFilePath(instance)
        if not os.path.exists(log_file):
            _CreateBlankFile(log_file, constants.SECURE_FILE_MODE)

        try:
            sda_dev_path = block_devices[0][1]
            # LXC needs to use partition mapping devices to access each partition
            # of the storage
            sda_dev_path = self._PrepareInstanceRootFsBdev(sda_dev_path, stash)
            conf_file = self._InstanceConfFilePath(instance.name)
            conf = self._CreateConfigFile(instance, sda_dev_path)
            utils.WriteFile(conf_file, data=conf)

            logging.info("Starting LXC container")
            try:
                self._SpawnLXC(instance, log_file, conf_file)
            except:
                logging.error(
                    "Failed to start instance %s. Please take a look at %s to"
                    " see LXC errors.", instance.name, log_file)
                raise
        except:
            # Save the original error
            exc_info = sys.exc_info()
            try:
                self._CleanupInstance(instance.name, stash)
            except HypervisorError as err:
                logging.warn("Cleanup for instance %s incomplete: %s",
                             instance.name, err)
            raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])

        self._SaveInstanceStash(instance.name, stash)
예제 #5
0
파일: ssh.py 프로젝트: sajalcody/ganeti
def GetUserFiles(user,
                 mkdir=False,
                 dircheck=True,
                 kind=constants.SSHK_DSA,
                 _homedir_fn=None):
    """Return the paths of a user's SSH files.

  @type user: string
  @param user: Username
  @type mkdir: bool
  @param mkdir: Whether to create ".ssh" directory if it doesn't exist
  @type dircheck: bool
  @param dircheck: Whether to check if ".ssh" directory exists
  @type kind: string
  @param kind: One of L{constants.SSHK_ALL}
  @rtype: tuple; (string, string, string)
  @return: Tuple containing three file system paths; the private SSH key file,
    the public SSH key file and the user's C{authorized_keys} file
  @raise errors.OpExecError: When home directory of the user can not be
    determined
  @raise errors.OpExecError: Regardless of the C{mkdir} parameters, this
    exception is raised if C{~$user/.ssh} is not a directory and C{dircheck}
    is set to C{True}

  """
    if _homedir_fn is None:
        _homedir_fn = utils.GetHomeDir

    user_dir = _homedir_fn(user)
    if not user_dir:
        raise errors.OpExecError("Cannot resolve home of user '%s'" % user)

    if kind == constants.SSHK_DSA:
        suffix = "dsa"
    elif kind == constants.SSHK_RSA:
        suffix = "rsa"
    elif kind == constants.SSHK_ECDSA:
        suffix = "ecdsa"
    else:
        raise errors.ProgrammerError("Unknown SSH key kind '%s'" % kind)

    ssh_dir = utils.PathJoin(user_dir, ".ssh")
    if mkdir:
        utils.EnsureDirs([(ssh_dir, constants.SECURE_DIR_MODE)])
    elif dircheck and not os.path.isdir(ssh_dir):
        raise errors.OpExecError("Path %s is not a directory" % ssh_dir)

    return [
        utils.PathJoin(ssh_dir, base) for base in
        ["id_%s" %
         suffix, "id_%s.pub" % suffix, "authorized_keys"]
    ]
예제 #6
0
    def StartInstance(self, instance, block_devices, startup_paused):
        """Start an instance.

    For LXC, we try to mount the block device and execute 'lxc-start'.
    We use volatile containers.

    """
        root_dir = self._InstanceDir(instance.name)
        try:
            utils.EnsureDirs([(root_dir, self._DIR_MODE)])
        except errors.GenericError, err:
            raise HypervisorError("Creating instance directory failed: %s",
                                  str(err))
예제 #7
0
    def StartInstance(self, instance, block_devices, startup_paused):
        """Start an instance.

    For LXC, we try to mount the block device and execute 'lxc-start'.
    We use volatile containers.

    """
        stash = {}

        # Since LXC version >= 1.0.0, the LXC strictly requires all cgroup
        # subsystems mounted before starting a container.
        # Try to mount all cgroup subsystems needed to start a LXC container.
        self._EnsureCgroupMounts(instance.hvparams)

        root_dir = self._InstanceDir(instance.name)
        try:
            utils.EnsureDirs([(root_dir, self._DIR_MODE)])
        except errors.GenericError, err:
            raise HypervisorError("Creating instance directory failed: %s",
                                  str(err))
예제 #8
0
def InitCluster(
        cluster_name,
        mac_prefix,  # pylint: disable=R0913, R0914
        master_netmask,
        master_netdev,
        file_storage_dir,
        shared_file_storage_dir,
        gluster_storage_dir,
        candidate_pool_size,
        secondary_ip=None,
        vg_name=None,
        beparams=None,
        nicparams=None,
        ndparams=None,
        hvparams=None,
        diskparams=None,
        enabled_hypervisors=None,
        modify_etc_hosts=True,
        modify_ssh_setup=True,
        maintain_node_health=False,
        drbd_helper=None,
        uid_pool=None,
        default_iallocator=None,
        default_iallocator_params=None,
        primary_ip_version=None,
        ipolicy=None,
        prealloc_wipe_disks=False,
        use_external_mip_script=False,
        hv_state=None,
        disk_state=None,
        enabled_disk_templates=None,
        install_image=None,
        zeroing_image=None,
        compression_tools=None,
        enabled_user_shutdown=False):
    """Initialise the cluster.

  @type candidate_pool_size: int
  @param candidate_pool_size: master candidate pool size

  @type enabled_disk_templates: list of string
  @param enabled_disk_templates: list of disk_templates to be used in this
    cluster

  @type enabled_user_shutdown: bool
  @param enabled_user_shutdown: whether user shutdown is enabled cluster
                                wide

  """
    # TODO: complete the docstring
    if config.ConfigWriter.IsCluster():
        raise errors.OpPrereqError("Cluster is already initialised",
                                   errors.ECODE_STATE)

    data_dir = vcluster.AddNodePrefix(pathutils.DATA_DIR)
    queue_dir = vcluster.AddNodePrefix(pathutils.QUEUE_DIR)
    archive_dir = vcluster.AddNodePrefix(pathutils.JOB_QUEUE_ARCHIVE_DIR)
    for ddir in [queue_dir, data_dir, archive_dir]:
        if os.path.isdir(ddir):
            for entry in os.listdir(ddir):
                if not os.path.isdir(os.path.join(ddir, entry)):
                    raise errors.OpPrereqError(
                        "%s contains non-directory entries like %s. Remove left-overs of an"
                        " old cluster before initialising a new one" %
                        (ddir, entry), errors.ECODE_STATE)

    if not enabled_hypervisors:
        raise errors.OpPrereqError(
            "Enabled hypervisors list must contain at"
            " least one member", errors.ECODE_INVAL)
    invalid_hvs = set(enabled_hypervisors) - constants.HYPER_TYPES
    if invalid_hvs:
        raise errors.OpPrereqError(
            "Enabled hypervisors contains invalid"
            " entries: %s" % invalid_hvs, errors.ECODE_INVAL)

    _InitCheckEnabledDiskTemplates(enabled_disk_templates)

    try:
        ipcls = netutils.IPAddress.GetClassFromIpVersion(primary_ip_version)
    except errors.ProgrammerError:
        raise errors.OpPrereqError(
            "Invalid primary ip version: %d." % primary_ip_version,
            errors.ECODE_INVAL)

    hostname = netutils.GetHostname(family=ipcls.family)
    if not ipcls.IsValid(hostname.ip):
        raise errors.OpPrereqError(
            "This host's IP (%s) is not a valid IPv%d"
            " address." % (hostname.ip, primary_ip_version),
            errors.ECODE_INVAL)

    if ipcls.IsLoopback(hostname.ip):
        raise errors.OpPrereqError(
            "This host's IP (%s) resolves to a loopback"
            " address. Please fix DNS or %s." %
            (hostname.ip, pathutils.ETC_HOSTS), errors.ECODE_ENVIRON)

    if not ipcls.Own(hostname.ip):
        raise errors.OpPrereqError(
            "Inconsistency: this host's name resolves"
            " to %s,\nbut this ip address does not"
            " belong to this host" % hostname.ip, errors.ECODE_ENVIRON)

    clustername = netutils.GetHostname(name=cluster_name, family=ipcls.family)

    if netutils.TcpPing(clustername.ip,
                        constants.DEFAULT_NODED_PORT,
                        timeout=5):
        raise errors.OpPrereqError("Cluster IP already active",
                                   errors.ECODE_NOTUNIQUE)

    if not secondary_ip:
        if primary_ip_version == constants.IP6_VERSION:
            raise errors.OpPrereqError(
                "When using a IPv6 primary address, a valid"
                " IPv4 address must be given as secondary", errors.ECODE_INVAL)
        secondary_ip = hostname.ip

    if not netutils.IP4Address.IsValid(secondary_ip):
        raise errors.OpPrereqError(
            "Secondary IP address (%s) has to be a valid"
            " IPv4 address." % secondary_ip, errors.ECODE_INVAL)

    if not netutils.IP4Address.Own(secondary_ip):
        raise errors.OpPrereqError(
            "You gave %s as secondary IP,"
            " but it does not belong to this host." % secondary_ip,
            errors.ECODE_ENVIRON)

    if master_netmask is not None:
        if not ipcls.ValidateNetmask(master_netmask):
            raise errors.OpPrereqError(
                "CIDR netmask (%s) not valid for IPv%s " %
                (master_netmask, primary_ip_version), errors.ECODE_INVAL)
    else:
        master_netmask = ipcls.iplen

    if vg_name:
        # Check if volume group is valid
        vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(),
                                              vg_name, constants.MIN_VG_SIZE)
        if vgstatus:
            raise errors.OpPrereqError("Error: %s" % vgstatus,
                                       errors.ECODE_INVAL)

    drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
    _InitCheckDrbdHelper(drbd_helper, drbd_enabled)

    logging.debug("Stopping daemons (if any are running)")
    result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop-all"])
    if result.failed:
        raise errors.OpExecError("Could not stop daemons, command %s"
                                 " had exitcode %s and error '%s'" %
                                 (result.cmd, result.exit_code, result.output))

    file_storage_dir = _PrepareFileStorage(enabled_disk_templates,
                                           file_storage_dir)
    shared_file_storage_dir = _PrepareSharedFileStorage(
        enabled_disk_templates, shared_file_storage_dir)
    gluster_storage_dir = _PrepareGlusterStorage(enabled_disk_templates,
                                                 gluster_storage_dir)

    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$", mac_prefix):
        raise errors.OpPrereqError(
            "Invalid mac prefix given '%s'" % mac_prefix, errors.ECODE_INVAL)

    if not nicparams.get('mode', None) == constants.NIC_MODE_OVS:
        # Do not do this check if mode=openvswitch, since the openvswitch is not
        # created yet
        result = utils.RunCmd(["ip", "link", "show", "dev", master_netdev])
        if result.failed:
            raise errors.OpPrereqError(
                "Invalid master netdev given (%s): '%s'" %
                (master_netdev, result.output.strip()), errors.ECODE_INVAL)

    dirs = [(pathutils.RUN_DIR, constants.RUN_DIRS_MODE)]
    utils.EnsureDirs(dirs)

    objects.UpgradeBeParams(beparams)
    utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
    utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)

    objects.NIC.CheckParameterSyntax(nicparams)

    full_ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy)
    _RestrictIpolicyToEnabledDiskTemplates(full_ipolicy,
                                           enabled_disk_templates)

    if ndparams is not None:
        utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
    else:
        ndparams = dict(constants.NDC_DEFAULTS)

    # This is ugly, as we modify the dict itself
    # FIXME: Make utils.ForceDictType pure functional or write a wrapper
    # around it
    if hv_state:
        for hvname, hvs_data in hv_state.items():
            utils.ForceDictType(hvs_data, constants.HVSTS_PARAMETER_TYPES)
            hv_state[hvname] = objects.Cluster.SimpleFillHvState(hvs_data)
    else:
        hv_state = dict((hvname, constants.HVST_DEFAULTS)
                        for hvname in enabled_hypervisors)

    # FIXME: disk_state has no default values yet
    if disk_state:
        for storage, ds_data in disk_state.items():
            if storage not in constants.DS_VALID_TYPES:
                raise errors.OpPrereqError(
                    "Invalid storage type in disk state: %s" % storage,
                    errors.ECODE_INVAL)
            for ds_name, state in ds_data.items():
                utils.ForceDictType(state, constants.DSS_PARAMETER_TYPES)
                ds_data[ds_name] = objects.Cluster.SimpleFillDiskState(state)

    # hvparams is a mapping of hypervisor->hvparams dict
    for hv_name, hv_params in hvparams.iteritems():
        utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
        hv_class = hypervisor.GetHypervisor(hv_name)
        hv_class.CheckParameterSyntax(hv_params)

    # diskparams is a mapping of disk-template->diskparams dict
    for template, dt_params in diskparams.items():
        param_keys = set(dt_params.keys())
        default_param_keys = set(constants.DISK_DT_DEFAULTS[template].keys())
        if not (param_keys <= default_param_keys):
            unknown_params = param_keys - default_param_keys
            raise errors.OpPrereqError(
                "Invalid parameters for disk template %s:"
                " %s" % (template, utils.CommaJoin(unknown_params)),
                errors.ECODE_INVAL)
        utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
        if template == constants.DT_DRBD8 and vg_name is not None:
            # The default METAVG value is equal to the VG name set at init time,
            # if provided
            dt_params[constants.DRBD_DEFAULT_METAVG] = vg_name

    try:
        utils.VerifyDictOptions(diskparams, constants.DISK_DT_DEFAULTS)
    except errors.OpPrereqError, err:
        raise errors.OpPrereqError("While verify diskparam options: %s" % err,
                                   errors.ECODE_INVAL)
예제 #9
0
 def __init__(self):
     hv_base.BaseHypervisor.__init__(self)
     utils.EnsureDirs([(self._ROOT_DIR, constants.RUN_DIRS_MODE)])
예제 #10
0
 def __init__(self):
     hv_base.BaseHypervisor.__init__(self)
     utils.EnsureDirs([(self._ROOT_DIR, self._DIR_MODE)])
예제 #11
0
파일: uidpool.py 프로젝트: volans-/ganeti
def RequestUnusedUid(all_uids):
    """Tries to find an unused uid from the uid-pool, locks it and returns it.

  Usage pattern
  =============

  1. When starting a process::

      from ganeti import ssconf
      from ganeti import uidpool

      # Get list of all user-ids in the uid-pool from ssconf
      ss = ssconf.SimpleStore()
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
      all_uids = set(uidpool.ExpandUidPool(uid_pool))

      uid = uidpool.RequestUnusedUid(all_uids)
      try:
        <start a process with the UID>
        # Once the process is started, we can release the file lock
        uid.Unlock()
      except ... as err:
        # Return the UID to the pool
        uidpool.ReleaseUid(uid)

  2. Stopping a process::

      from ganeti import uidpool

      uid = <get the UID the process is running under>
      <stop the process>
      uidpool.ReleaseUid(uid)

  @type all_uids: set of integers
  @param all_uids: a set containing all the user-ids in the user-id pool
  @return: a LockedUid object representing the unused uid. It's the caller's
           responsibility to unlock the uid once an instance is started with
           this uid.

  """
    # Create the lock dir if it's not yet present
    try:
        utils.EnsureDirs([(pathutils.UIDPOOL_LOCKDIR, 0o755)])
    except errors.GenericError as err:
        raise errors.LockError("Failed to create user-id pool lock dir: %s" %
                               err)

    # Get list of currently used uids from the filesystem
    try:
        taken_uids = set()
        for taken_uid in os.listdir(pathutils.UIDPOOL_LOCKDIR):
            try:
                taken_uid = int(taken_uid)
            except ValueError as err:
                # Skip directory entries that can't be converted into an integer
                continue
            taken_uids.add(taken_uid)
    except OSError as err:
        raise errors.LockError("Failed to get list of used user-ids: %s" % err)

    # Filter out spurious entries from the directory listing
    taken_uids = all_uids.intersection(taken_uids)

    # Remove the list of used uids from the list of all uids
    unused_uids = list(all_uids - taken_uids)
    if not unused_uids:
        logging.info("All user-ids in the uid-pool are marked 'taken'")

    # Randomize the order of the unused user-id list
    random.shuffle(unused_uids)

    # Randomize the order of the unused user-id list
    taken_uids = list(taken_uids)
    random.shuffle(taken_uids)

    for uid in unused_uids + taken_uids:
        try:
            # Create the lock file
            # Note: we don't care if it exists. Only the fact that we can
            # (or can't) lock it later is what matters.
            uid_path = utils.PathJoin(pathutils.UIDPOOL_LOCKDIR, str(uid))
            lock = utils.FileLock.Open(uid_path)
        except OSError as err:
            raise errors.LockError(
                "Failed to create lockfile for user-id %s: %s" % (uid, err))
        try:
            # Try acquiring an exclusive lock on the lock file
            lock.Exclusive()
            # Check if there is any process running with this user-id
            if _IsUidUsed(uid):
                logging.debug(
                    "There is already a process running under"
                    " user-id %s", uid)
                lock.Unlock()
                continue
            return LockedUid(uid, lock)
        except IOError as err:
            if err.errno == errno.EAGAIN:
                # The file is already locked, let's skip it and try another unused uid
                logging.debug("Lockfile for user-id is already locked %s: %s",
                              uid, err)
                continue
        except errors.LockError as err:
            # There was an unexpected error while trying to lock the file
            logging.error("Failed to lock the lockfile for user-id %s: %s",
                          uid, err)
            raise

    raise errors.LockError("Failed to find an unused user-id")
예제 #12
0
파일: bootstrap.py 프로젝트: vali-um/ganeti
def InitCluster(
        cluster_name,
        mac_prefix,  # pylint: disable=R0913, R0914
        master_netmask,
        master_netdev,
        file_storage_dir,
        shared_file_storage_dir,
        gluster_storage_dir,
        candidate_pool_size,
        ssh_key_type,
        ssh_key_bits,
        secondary_ip=None,
        vg_name=None,
        beparams=None,
        nicparams=None,
        ndparams=None,
        hvparams=None,
        diskparams=None,
        enabled_hypervisors=None,
        modify_etc_hosts=True,
        modify_ssh_setup=True,
        maintain_node_health=False,
        drbd_helper=None,
        uid_pool=None,
        default_iallocator=None,
        default_iallocator_params=None,
        primary_ip_version=None,
        ipolicy=None,
        prealloc_wipe_disks=False,
        use_external_mip_script=False,
        hv_state=None,
        disk_state=None,
        enabled_disk_templates=None,
        install_image=None,
        zeroing_image=None,
        compression_tools=None,
        enabled_user_shutdown=False):
    """Initialise the cluster.

  @type candidate_pool_size: int
  @param candidate_pool_size: master candidate pool size

  @type enabled_disk_templates: list of string
  @param enabled_disk_templates: list of disk_templates to be used in this
    cluster

  @type enabled_user_shutdown: bool
  @param enabled_user_shutdown: whether user shutdown is enabled cluster
                                wide

  """
    # TODO: complete the docstring
    if config.ConfigWriter.IsCluster():
        raise errors.OpPrereqError("Cluster is already initialised",
                                   errors.ECODE_STATE)

    data_dir = vcluster.AddNodePrefix(pathutils.DATA_DIR)
    queue_dir = vcluster.AddNodePrefix(pathutils.QUEUE_DIR)
    archive_dir = vcluster.AddNodePrefix(pathutils.JOB_QUEUE_ARCHIVE_DIR)
    for ddir in [queue_dir, data_dir, archive_dir]:
        if os.path.isdir(ddir):
            for entry in os.listdir(ddir):
                if not os.path.isdir(os.path.join(ddir, entry)):
                    raise errors.OpPrereqError(
                        "%s contains non-directory entries like %s. Remove left-overs of an"
                        " old cluster before initialising a new one" %
                        (ddir, entry), errors.ECODE_STATE)

    if not enabled_hypervisors:
        raise errors.OpPrereqError(
            "Enabled hypervisors list must contain at"
            " least one member", errors.ECODE_INVAL)
    invalid_hvs = set(enabled_hypervisors) - constants.HYPER_TYPES
    if invalid_hvs:
        raise errors.OpPrereqError(
            "Enabled hypervisors contains invalid"
            " entries: %s" % invalid_hvs, errors.ECODE_INVAL)

    _InitCheckEnabledDiskTemplates(enabled_disk_templates)

    try:
        ipcls = netutils.IPAddress.GetClassFromIpVersion(primary_ip_version)
    except errors.ProgrammerError:
        raise errors.OpPrereqError(
            "Invalid primary ip version: %d." % primary_ip_version,
            errors.ECODE_INVAL)

    hostname = netutils.GetHostname(family=ipcls.family)
    if not ipcls.IsValid(hostname.ip):
        raise errors.OpPrereqError(
            "This host's IP (%s) is not a valid IPv%d"
            " address." % (hostname.ip, primary_ip_version),
            errors.ECODE_INVAL)

    if ipcls.IsLoopback(hostname.ip):
        raise errors.OpPrereqError(
            "This host's IP (%s) resolves to a loopback"
            " address. Please fix DNS or %s." %
            (hostname.ip, pathutils.ETC_HOSTS), errors.ECODE_ENVIRON)

    if not ipcls.Own(hostname.ip):
        raise errors.OpPrereqError(
            "Inconsistency: this host's name resolves"
            " to %s,\nbut this ip address does not"
            " belong to this host" % hostname.ip, errors.ECODE_ENVIRON)

    clustername = netutils.GetHostname(name=cluster_name, family=ipcls.family)

    if netutils.TcpPing(clustername.ip,
                        constants.DEFAULT_NODED_PORT,
                        timeout=5):
        raise errors.OpPrereqError("Cluster IP already active",
                                   errors.ECODE_NOTUNIQUE)

    if not secondary_ip:
        if primary_ip_version == constants.IP6_VERSION:
            raise errors.OpPrereqError(
                "When using a IPv6 primary address, a valid"
                " IPv4 address must be given as secondary", errors.ECODE_INVAL)
        secondary_ip = hostname.ip

    if not netutils.IP4Address.IsValid(secondary_ip):
        raise errors.OpPrereqError(
            "Secondary IP address (%s) has to be a valid"
            " IPv4 address." % secondary_ip, errors.ECODE_INVAL)

    if not netutils.IP4Address.Own(secondary_ip):
        raise errors.OpPrereqError(
            "You gave %s as secondary IP,"
            " but it does not belong to this host." % secondary_ip,
            errors.ECODE_ENVIRON)

    if master_netmask is not None:
        if not ipcls.ValidateNetmask(master_netmask):
            raise errors.OpPrereqError(
                "CIDR netmask (%s) not valid for IPv%s " %
                (master_netmask, primary_ip_version), errors.ECODE_INVAL)
    else:
        master_netmask = ipcls.iplen

    if vg_name:
        # Check if volume group is valid
        vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(),
                                              vg_name, constants.MIN_VG_SIZE)
        if vgstatus:
            raise errors.OpPrereqError("Error: %s" % vgstatus,
                                       errors.ECODE_INVAL)

    drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
    _InitCheckDrbdHelper(drbd_helper, drbd_enabled)

    logging.debug("Stopping daemons (if any are running)")
    result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop-all"])
    if result.failed:
        raise errors.OpExecError("Could not stop daemons, command %s"
                                 " had exitcode %s and error '%s'" %
                                 (result.cmd, result.exit_code, result.output))

    file_storage_dir = _PrepareFileStorage(enabled_disk_templates,
                                           file_storage_dir)
    shared_file_storage_dir = _PrepareSharedFileStorage(
        enabled_disk_templates, shared_file_storage_dir)
    gluster_storage_dir = _PrepareGlusterStorage(enabled_disk_templates,
                                                 gluster_storage_dir)

    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$", mac_prefix):
        raise errors.OpPrereqError(
            "Invalid mac prefix given '%s'" % mac_prefix, errors.ECODE_INVAL)

    if not nicparams.get('mode', None) == constants.NIC_MODE_OVS:
        # Do not do this check if mode=openvswitch, since the openvswitch is not
        # created yet
        result = utils.RunCmd(["ip", "link", "show", "dev", master_netdev])
        if result.failed:
            raise errors.OpPrereqError(
                "Invalid master netdev given (%s): '%s'" %
                (master_netdev, result.output.strip()), errors.ECODE_INVAL)

    dirs = [(pathutils.RUN_DIR, constants.RUN_DIRS_MODE)]
    utils.EnsureDirs(dirs)

    objects.UpgradeBeParams(beparams)
    utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
    utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)

    objects.NIC.CheckParameterSyntax(nicparams)

    full_ipolicy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy)
    _RestrictIpolicyToEnabledDiskTemplates(full_ipolicy,
                                           enabled_disk_templates)

    if ndparams is not None:
        utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
    else:
        ndparams = dict(constants.NDC_DEFAULTS)

    # This is ugly, as we modify the dict itself
    # FIXME: Make utils.ForceDictType pure functional or write a wrapper
    # around it
    if hv_state:
        for hvname, hvs_data in hv_state.items():
            utils.ForceDictType(hvs_data, constants.HVSTS_PARAMETER_TYPES)
            hv_state[hvname] = objects.Cluster.SimpleFillHvState(hvs_data)
    else:
        hv_state = dict((hvname, constants.HVST_DEFAULTS)
                        for hvname in enabled_hypervisors)

    # FIXME: disk_state has no default values yet
    if disk_state:
        for storage, ds_data in disk_state.items():
            if storage not in constants.DS_VALID_TYPES:
                raise errors.OpPrereqError(
                    "Invalid storage type in disk state: %s" % storage,
                    errors.ECODE_INVAL)
            for ds_name, state in ds_data.items():
                utils.ForceDictType(state, constants.DSS_PARAMETER_TYPES)
                ds_data[ds_name] = objects.Cluster.SimpleFillDiskState(state)

    # hvparams is a mapping of hypervisor->hvparams dict
    for hv_name, hv_params in hvparams.items():
        utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
        hv_class = hypervisor.GetHypervisor(hv_name)
        hv_class.CheckParameterSyntax(hv_params)

    # diskparams is a mapping of disk-template->diskparams dict
    for template, dt_params in diskparams.items():
        param_keys = set(dt_params.keys())
        default_param_keys = set(constants.DISK_DT_DEFAULTS[template].keys())
        if param_keys > default_param_keys:
            unknown_params = param_keys - default_param_keys
            raise errors.OpPrereqError(
                "Invalid parameters for disk template %s:"
                " %s" % (template, utils.CommaJoin(unknown_params)),
                errors.ECODE_INVAL)
        utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
        if template == constants.DT_DRBD8 and vg_name is not None:
            # The default METAVG value is equal to the VG name set at init time,
            # if provided
            dt_params[constants.DRBD_DEFAULT_METAVG] = vg_name

    try:
        utils.VerifyDictOptions(diskparams, constants.DISK_DT_DEFAULTS)
    except errors.OpPrereqError as err:
        raise errors.OpPrereqError("While verify diskparam options: %s" % err,
                                   errors.ECODE_INVAL)

    # set up ssh config and /etc/hosts
    rsa_sshkey = ""
    dsa_sshkey = ""
    if os.path.isfile(pathutils.SSH_HOST_RSA_PUB):
        sshline = utils.ReadFile(pathutils.SSH_HOST_RSA_PUB)
        rsa_sshkey = sshline.split(" ")[1]
    if os.path.isfile(pathutils.SSH_HOST_DSA_PUB):
        sshline = utils.ReadFile(pathutils.SSH_HOST_DSA_PUB)
        dsa_sshkey = sshline.split(" ")[1]
    if not rsa_sshkey and not dsa_sshkey:
        raise errors.OpPrereqError("Failed to find SSH public keys",
                                   errors.ECODE_ENVIRON)

    if modify_etc_hosts:
        utils.AddHostToEtcHosts(hostname.name, hostname.ip)

    if modify_ssh_setup:
        ssh.InitSSHSetup(ssh_key_type, ssh_key_bits)

    if default_iallocator is not None:
        alloc_script = utils.FindFile(default_iallocator,
                                      constants.IALLOCATOR_SEARCH_PATH,
                                      os.path.isfile)
        if alloc_script is None:
            raise errors.OpPrereqError(
                "Invalid default iallocator script '%s'"
                " specified" % default_iallocator, errors.ECODE_INVAL)
    else:
        # default to htools
        if utils.FindFile(constants.IALLOC_HAIL,
                          constants.IALLOCATOR_SEARCH_PATH, os.path.isfile):
            default_iallocator = constants.IALLOC_HAIL

    # check if we have all the users we need
    try:
        runtime.GetEnts()
    except errors.ConfigurationError as err:
        raise errors.OpPrereqError(
            "Required system user/group missing: %s" % err,
            errors.ECODE_ENVIRON)

    candidate_certs = {}

    now = time.time()

    if compression_tools is not None:
        cluster.CheckCompressionTools(compression_tools)

    initial_dc_config = dict(active=True,
                             interval=int(constants.MOND_TIME_INTERVAL * 1e6))
    data_collectors = dict((name, initial_dc_config.copy())
                           for name in constants.DATA_COLLECTOR_NAMES)

    # init of cluster config file
    cluster_config = objects.Cluster(
        serial_no=1,
        rsahostkeypub=rsa_sshkey,
        dsahostkeypub=dsa_sshkey,
        highest_used_port=(constants.FIRST_DRBD_PORT - 1),
        mac_prefix=mac_prefix,
        volume_group_name=vg_name,
        tcpudp_port_pool=set(),
        master_ip=clustername.ip,
        master_netmask=master_netmask,
        master_netdev=master_netdev,
        cluster_name=clustername.name,
        file_storage_dir=file_storage_dir,
        shared_file_storage_dir=shared_file_storage_dir,
        gluster_storage_dir=gluster_storage_dir,
        enabled_hypervisors=enabled_hypervisors,
        beparams={constants.PP_DEFAULT: beparams},
        nicparams={constants.PP_DEFAULT: nicparams},
        ndparams=ndparams,
        hvparams=hvparams,
        diskparams=diskparams,
        candidate_pool_size=candidate_pool_size,
        modify_etc_hosts=modify_etc_hosts,
        modify_ssh_setup=modify_ssh_setup,
        uid_pool=uid_pool,
        ctime=now,
        mtime=now,
        maintain_node_health=maintain_node_health,
        data_collectors=data_collectors,
        drbd_usermode_helper=drbd_helper,
        default_iallocator=default_iallocator,
        default_iallocator_params=default_iallocator_params,
        primary_ip_family=ipcls.family,
        prealloc_wipe_disks=prealloc_wipe_disks,
        use_external_mip_script=use_external_mip_script,
        ipolicy=full_ipolicy,
        hv_state_static=hv_state,
        disk_state_static=disk_state,
        enabled_disk_templates=enabled_disk_templates,
        candidate_certs=candidate_certs,
        osparams={},
        osparams_private_cluster={},
        install_image=install_image,
        zeroing_image=zeroing_image,
        compression_tools=compression_tools,
        enabled_user_shutdown=enabled_user_shutdown,
        ssh_key_type=ssh_key_type,
        ssh_key_bits=ssh_key_bits,
    )
    master_node_config = objects.Node(
        name=hostname.name,
        primary_ip=hostname.ip,
        secondary_ip=secondary_ip,
        serial_no=1,
        master_candidate=True,
        offline=False,
        drained=False,
        ctime=now,
        mtime=now,
    )
    InitConfig(constants.CONFIG_VERSION, cluster_config, master_node_config)
    cfg = config.ConfigWriter(offline=True)
    ssh.WriteKnownHostsFile(cfg, pathutils.SSH_KNOWN_HOSTS_FILE)
    cfg.Update(cfg.GetClusterInfo(), logging.error)
    ssconf.WriteSsconfFiles(cfg.GetSsconfValues())

    master_uuid = cfg.GetMasterNode()
    if modify_ssh_setup:
        ssh.InitPubKeyFile(master_uuid, ssh_key_type)
    # set up the inter-node password and certificate
    _InitGanetiServerSetup(hostname.name, cfg)

    logging.debug("Starting daemons")
    result = utils.RunCmd([pathutils.DAEMON_UTIL, "start-all"])
    if result.failed:
        raise errors.OpExecError("Could not start daemons, command %s"
                                 " had exitcode %s and error %s" %
                                 (result.cmd, result.exit_code, result.output))

    _WaitForMasterDaemon()