Interface between salt.cloud.lxc driver and lxc.init
    ``vm_`` is a mapping of vm opts in the salt.cloud format
    as documented for the lxc driver.

    This can be used either:

    - from the salt cloud driver
    - because you find the argument to give easier here
      than using directly lxc.init

    .. warning::
        BE REALLY CAREFUL CHANGING DEFAULTS !!!
        IT'S A RETRO COMPATIBLE INTERFACE WITH
        THE SALT CLOUD DRIVER (ask kiorky).

    name
        name of the lxc container to create
    pub_key
        public key to preseed the minion with.
        Can be the keycontent or a filepath
    priv_key
        private key to preseed the minion with.
        Can be the keycontent or a filepath
    path
        path to the container parent directory (default: /var/lib/lxc)

        .. versionadded:: 2015.8.0

    profile
        :ref:`profile <tutorial-lxc-profiles-container>` selection
    network_profile
        :ref:`network profile <tutorial-lxc-profiles-network>` selection
    nic_opts
        per interface settings compatibles with
        network profile (ipv4/ipv6/link/gateway/mac/netmask)

        eg::

              - {'eth0': {'mac': '00:16:3e:01:29:40',
                          'gateway': None, (default)
                          'link': 'br0', (default)
                          'gateway': None, (default)
                          'netmask': '', (default)
                          'ip': '22.1.4.25'}}
    unconditional_install
        given to lxc.bootstrap (see relative doc)
    force_install
        given to lxc.bootstrap (see relative doc)
    config
        any extra argument for the salt minion config
    dnsservers
        list of DNS servers to set inside the container
    dns_via_dhcp
        do not set the dns servers, let them be set by the dhcp.
    autostart
        autostart the container at boot time
    password
        administrative password for the container
    bootstrap_delay
        delay before launching bootstrap script at Container init


    .. warning::

        Legacy but still supported options:

        from_container
            which container we use as a template
            when running lxc.clone
        image
            which template do we use when we
            are using lxc.create. This is the default
            mode unless you specify something in from_container
        backing
            which backing store to use.
            Values can be: overlayfs, dir(default), lvm, zfs, brtfs
        fstype
            When using a blockdevice level backing store,
            which filesystem to use on
        size
            When using a blockdevice level backing store,
            which size for the filesystem to use on
        snapshot
            Use snapshot when cloning the container source
        vgname
            if using LVM: vgname
        lvname
            if using LVM: lvname
        thinpool:
            if using LVM: thinpool
        ip
            ip for the primary nic
        mac
            mac address for the primary nic
        netmask
            netmask for the primary nic (24)
            = ``vm_.get('netmask', '24')``
        bridge
            bridge for the primary nic (lxcbr0)
        gateway
            network gateway for the container
        additional_ips
            additional ips which will be wired on the main bridge (br0)
            which is connected to internet.
            Be aware that you may use manual virtual mac addresses
            providen by you provider (online, ovh, etc).
            This is a list of mappings {ip: '', mac: '', netmask:''}
            Set gateway to None and an interface with a gateway
            to escape from another interface that eth0.
            eg::

                  - {'mac': '00:16:3e:01:29:40',
                     'gateway': None, (default)
                     'link': 'br0', (default)
                     'netmask': '', (default)
                     'ip': '22.1.4.25'}

        users
            administrative users for the container
            default: [root] and [root, ubuntu] on ubuntu
        default_nic
            name of the first interface, you should
            really not override this

    CLI Example:

    .. code-block:: bash

        salt '*' lxc.cloud_init_interface foo

def cloud_init_interface(name, vm_=None, **kwargs):
    '''
    Interface between salt.cloud.lxc driver and lxc.init
    ``vm_`` is a mapping of vm opts in the salt.cloud format
    as documented for the lxc driver.

    This can be used either:

    - from the salt cloud driver
    - because you find the argument to give easier here
      than using directly lxc.init

    .. warning::
        BE REALLY CAREFUL CHANGING DEFAULTS !!!
        IT'S A RETRO COMPATIBLE INTERFACE WITH
        THE SALT CLOUD DRIVER (ask kiorky).

    name
        name of the lxc container to create
    pub_key
        public key to preseed the minion with.
        Can be the keycontent or a filepath
    priv_key
        private key to preseed the minion with.
        Can be the keycontent or a filepath
    path
        path to the container parent directory (default: /var/lib/lxc)

        .. versionadded:: 2015.8.0

    profile
        :ref:`profile <tutorial-lxc-profiles-container>` selection
    network_profile
        :ref:`network profile <tutorial-lxc-profiles-network>` selection
    nic_opts
        per interface settings compatibles with
        network profile (ipv4/ipv6/link/gateway/mac/netmask)

        eg::

              - {'eth0': {'mac': '00:16:3e:01:29:40',
                          'gateway': None, (default)
                          'link': 'br0', (default)
                          'gateway': None, (default)
                          'netmask': '', (default)
                          'ip': '22.1.4.25'}}
    unconditional_install
        given to lxc.bootstrap (see relative doc)
    force_install
        given to lxc.bootstrap (see relative doc)
    config
        any extra argument for the salt minion config
    dnsservers
        list of DNS servers to set inside the container
    dns_via_dhcp
        do not set the dns servers, let them be set by the dhcp.
    autostart
        autostart the container at boot time
    password
        administrative password for the container
    bootstrap_delay
        delay before launching bootstrap script at Container init


    .. warning::

        Legacy but still supported options:

        from_container
            which container we use as a template
            when running lxc.clone
        image
            which template do we use when we
            are using lxc.create. This is the default
            mode unless you specify something in from_container
        backing
            which backing store to use.
            Values can be: overlayfs, dir(default), lvm, zfs, brtfs
        fstype
            When using a blockdevice level backing store,
            which filesystem to use on
        size
            When using a blockdevice level backing store,
            which size for the filesystem to use on
        snapshot
            Use snapshot when cloning the container source
        vgname
            if using LVM: vgname
        lvname
            if using LVM: lvname
        thinpool:
            if using LVM: thinpool
        ip
            ip for the primary nic
        mac
            mac address for the primary nic
        netmask
            netmask for the primary nic (24)
            = ``vm_.get('netmask', '24')``
        bridge
            bridge for the primary nic (lxcbr0)
        gateway
            network gateway for the container
        additional_ips
            additional ips which will be wired on the main bridge (br0)
            which is connected to internet.
            Be aware that you may use manual virtual mac addresses
            providen by you provider (online, ovh, etc).
            This is a list of mappings {ip: '', mac: '', netmask:''}
            Set gateway to None and an interface with a gateway
            to escape from another interface that eth0.
            eg::

                  - {'mac': '00:16:3e:01:29:40',
                     'gateway': None, (default)
                     'link': 'br0', (default)
                     'netmask': '', (default)
                     'ip': '22.1.4.25'}

        users
            administrative users for the container
            default: [root] and [root, ubuntu] on ubuntu
        default_nic
            name of the first interface, you should
            really not override this

    CLI Example:

    .. code-block:: bash

        salt '*' lxc.cloud_init_interface foo

    '''
    if vm_ is None:
        vm_ = {}
    vm_ = copy.deepcopy(vm_)
    vm_ = salt.utils.dictupdate.update(vm_, kwargs)

    profile_data = copy.deepcopy(
        vm_.get('lxc_profile',
                vm_.get('profile', {})))
    if not isinstance(profile_data, (dict, six.string_types)):
        profile_data = {}
    profile = get_container_profile(profile_data)

    def _cloud_get(k, default=None):
        return vm_.get(k, profile.get(k, default))

    if name is None:
        name = vm_['name']
    # if we are on ubuntu, default to ubuntu
    default_template = ''
    if __grains__.get('os', '') in ['Ubuntu']:
        default_template = 'ubuntu'
    image = _cloud_get('image')
    if not image:
        _cloud_get('template', default_template)
    backing = _cloud_get('backing', 'dir')
    if image:
        profile['template'] = image
    vgname = _cloud_get('vgname', None)
    if vgname:
        profile['vgname'] = vgname
    if backing:
        profile['backing'] = backing
    snapshot = _cloud_get('snapshot', False)
    autostart = bool(_cloud_get('autostart', True))
    dnsservers = _cloud_get('dnsservers', [])
    dns_via_dhcp = _cloud_get('dns_via_dhcp', True)
    password = _cloud_get('password', 's3cr3t')
    password_encrypted = _cloud_get('password_encrypted', False)
    fstype = _cloud_get('fstype', None)
    lvname = _cloud_get('lvname', None)
    thinpool = _cloud_get('thinpool', None)
    pub_key = _cloud_get('pub_key', None)
    priv_key = _cloud_get('priv_key', None)
    size = _cloud_get('size', '20G')
    script = _cloud_get('script', None)
    script_args = _cloud_get('script_args', None)
    users = _cloud_get('users', None)
    if users is None:
        users = []
    ssh_username = _cloud_get('ssh_username', None)
    if ssh_username and (ssh_username not in users):
        users.append(ssh_username)
    network_profile = _cloud_get('network_profile', None)
    nic_opts = kwargs.get('nic_opts', None)
    netmask = _cloud_get('netmask', '24')
    path = _cloud_get('path', None)
    bridge = _cloud_get('bridge', None)
    gateway = _cloud_get('gateway', None)
    unconditional_install = _cloud_get('unconditional_install', False)
    force_install = _cloud_get('force_install', True)
    config = _get_salt_config(_cloud_get('config', {}), **vm_)
    default_nic = _cloud_get('default_nic', DEFAULT_NIC)
    # do the interface with lxc.init mainly via nic_opts
    # to avoid extra and confusing extra use cases.
    if not isinstance(nic_opts, dict):
        nic_opts = salt.utils.odict.OrderedDict()
    # have a reference to the default nic
    eth0 = nic_opts.setdefault(default_nic,
                               salt.utils.odict.OrderedDict())
    # lxc config is based of ifc order, be sure to use odicts.
    if not isinstance(nic_opts, salt.utils.odict.OrderedDict):
        bnic_opts = salt.utils.odict.OrderedDict()
        bnic_opts.update(nic_opts)
        nic_opts = bnic_opts
    gw = None
    # legacy salt.cloud scheme for network interfaces settings support
    bridge = _cloud_get('bridge', None)
    ip = _cloud_get('ip', None)
    mac = _cloud_get('mac', None)
    if ip:
        fullip = ip
        if netmask:
            fullip += '/{0}'.format(netmask)
        eth0['ipv4'] = fullip
        if mac is not None:
            eth0['mac'] = mac
    for ix, iopts in enumerate(_cloud_get("additional_ips", [])):
        ifh = "eth{0}".format(ix+1)
        ethx = nic_opts.setdefault(ifh, {})
        if gw is None:
            gw = iopts.get('gateway', ethx.get('gateway', None))
            if gw:
                # only one and only one default gateway is allowed !
                eth0.pop('gateway', None)
                gateway = None
                # even if the gateway if on default "eth0" nic
                # and we popped it will work
                # as we reinject or set it here.
                ethx['gateway'] = gw
        elink = iopts.get('link', ethx.get('link', None))
        if elink:
            ethx['link'] = elink
        # allow dhcp
        aip = iopts.get('ipv4', iopts.get('ip', None))
        if aip:
            ethx['ipv4'] = aip
        nm = iopts.get('netmask', '')
        if nm:
            ethx['ipv4'] += '/{0}'.format(nm)
        for i in ('mac', 'hwaddr'):
            if i in iopts:
                ethx['mac'] = iopts[i]
                break
        if 'mac' not in ethx:
            ethx['mac'] = salt.utils.network.gen_mac()
    # last round checking for unique gateway and such
    gw = None
    for ethx in [a for a in nic_opts]:
        ndata = nic_opts[ethx]
        if gw:
            ndata.pop('gateway', None)
        if 'gateway' in ndata:
            gw = ndata['gateway']
            gateway = None
    # only use a default bridge / gateway if we configured them
    # via the legacy salt cloud configuration style.
    # On other cases, we should rely on settings provided by the new
    # salt lxc network profile style configuration which can
    # be also be overridden or a per interface basis via the nic_opts dict.
    if bridge:
        eth0['link'] = bridge
    if gateway:
        eth0['gateway'] = gateway
    #
    lxc_init_interface = {}
    lxc_init_interface['name'] = name
    lxc_init_interface['config'] = config
    lxc_init_interface['memory'] = _cloud_get('memory', 0)  # nolimit
    lxc_init_interface['pub_key'] = pub_key
    lxc_init_interface['priv_key'] = priv_key
    lxc_init_interface['nic_opts'] = nic_opts
    for clone_from in ['clone_from', 'clone', 'from_container']:
        # clone_from should default to None if not available
        lxc_init_interface['clone_from'] = _cloud_get(clone_from, None)
        if lxc_init_interface['clone_from'] is not None:
            break
    lxc_init_interface['profile'] = profile
    lxc_init_interface['snapshot'] = snapshot
    lxc_init_interface['dnsservers'] = dnsservers
    lxc_init_interface['fstype'] = fstype
    lxc_init_interface['path'] = path
    lxc_init_interface['vgname'] = vgname
    lxc_init_interface['size'] = size
    lxc_init_interface['lvname'] = lvname
    lxc_init_interface['thinpool'] = thinpool
    lxc_init_interface['force_install'] = force_install
    lxc_init_interface['unconditional_install'] = (
        unconditional_install
    )
    lxc_init_interface['bootstrap_url'] = script
    lxc_init_interface['bootstrap_args'] = script_args
    lxc_init_interface['bootstrap_shell'] = _cloud_get('bootstrap_shell', 'sh')
    lxc_init_interface['bootstrap_delay'] = _cloud_get('bootstrap_delay', None)
    lxc_init_interface['autostart'] = autostart
    lxc_init_interface['users'] = users
    lxc_init_interface['password'] = password
    lxc_init_interface['password_encrypted'] = password_encrypted
    # be sure not to let objects goes inside the return
    # as this return will be msgpacked for use in the runner !
    lxc_init_interface['network_profile'] = network_profile
    for i in ['cpu', 'cpuset', 'cpushare']:
        if _cloud_get(i, None):
            try:
                lxc_init_interface[i] = vm_[i]
            except KeyError:
                lxc_init_interface[i] = profile[i]
    return lxc_init_interface