'Create a new Linode, deploy a Linux distribution, and boot
This call abstracts much of the functionality of provisioning a Linode
and getting it booted.  A global grant to add Linodes to the account is
required, as this call will result in a billing charge.
Note that there is a safety valve of 5 Linodes per hour, in order to
prevent a runaway script from ruining your day.
:keyword name: the name to assign the Linode (mandatory)
:type    name: ``str``
:keyword image: which distribution to deploy on the Linode (mandatory)
:type    image: :class:`NodeImage`
:keyword size: the plan size to create (mandatory)
:type    size: :class:`NodeSize`
:keyword auth: an SSH key or root password (mandatory)
:type    auth: :class:`NodeAuthSSHKey` or :class:`NodeAuthPassword`
:keyword location: which datacenter to create the Linode in
:type    location: :class:`NodeLocation`
:keyword ex_swap: size of the swap partition in MB (128)
:type    ex_swap: ``int``
:keyword ex_rsize: size of the root partition in MB (plan size - swap).
:type    ex_rsize: ``int``
:keyword ex_kernel: a kernel ID from avail.kernels (Latest 2.6 Stable).
:type    ex_kernel: ``str``
:keyword ex_payment: one of 1, 12, or 24; subscription length (1)
:type    ex_payment: ``int``
:keyword ex_comment: a small comment for the configuration (libcloud)
:type    ex_comment: ``str``
:keyword ex_private: whether or not to request a private IP (False)
:type    ex_private: ``bool``
:keyword lconfig: what to call the configuration (generated)
:type    lconfig: ``str``
:keyword lroot: what to call the root image (generated)
:type    lroot: ``str``
:keyword lswap: what to call the swap space (generated)
:type    lswap: ``str``
:return: Node representing the newly-created Linode
:rtype: :class:`Node`'

def create_node(self, **kwargs):

    name = kwargs['name']
    image = kwargs['image']
    size = kwargs['size']
    auth = self._get_and_check_auth(kwargs['auth'])
    if ('location' in kwargs):
        chosen = kwargs['location'].id
    elif self.datacenter:
        chosen = self.datacenter
    else:
        raise LinodeException(251, 'Need    to    select    a    datacenter    first')
    plans = self.list_sizes()
    if (size.id not in [p.id for p in plans]):
        raise LinodeException(251, 'Invalid    plan    ID    --    avail.plans')
    payment = ('1' if ('ex_payment' not in kwargs) else str(kwargs['ex_payment']))
    if (payment not in ['1', '12', '24']):
        raise LinodeException(251, 'Invalid    subscription    (1,    12,    24)')
    ssh = None
    root = None
    if isinstance(auth, NodeAuthSSHKey):
        ssh = auth.pubkey
    elif isinstance(auth, NodeAuthPassword):
        root = auth.password
    if ((not ssh) and (not root)):
        raise LinodeException(251, 'Need    SSH    key    or    root    password')
    if ((root is not None) and (len(root) < 6)):
        raise LinodeException(251, 'Root    password    is    too    short')
    try:
        swap = (128 if ('ex_swap' not in kwargs) else int(kwargs['ex_swap']))
    except:
        raise LinodeException(251, 'Need    an    integer    swap    size')
    imagesize = ((size.disk - swap) if ('ex_rsize' not in kwargs) else int(kwargs['ex_rsize']))
    if ((imagesize + swap) > size.disk):
        raise LinodeException(251, 'Total    disk    images    are    too    big')
    distros = self.list_images()
    if (image.id not in [d.id for d in distros]):
        raise LinodeException(251, 'Invalid    distro    --    avail.distributions')
    if ('ex_kernel' in kwargs):
        kernel = kwargs['ex_kernel']
    elif image.extra['64bit']:
        kernel = 138
    else:
        kernel = 137
    params = {'api_action': 'avail.kernels'}
    kernels = self.connection.request(API_ROOT, params=params).objects[0]
    if (kernel not in [z['KERNELID'] for z in kernels]):
        raise LinodeException(251, 'Invalid    kernel    --    avail.kernels')
    comments = ('Created    by    Apache    libcloud    <http://www.libcloud.org>' if ('ex_comment' not in kwargs) else kwargs['ex_comment'])
    params = {'api_action': 'linode.create', 'DatacenterID': chosen, 'PlanID': size.id, 'PaymentTerm': payment}
    data = self.connection.request(API_ROOT, params=params).objects[0]
    linode = {'id': data['LinodeID']}
    params = {'api_action': 'linode.update', 'LinodeID': linode['id'], 'Label': name}
    self.connection.request(API_ROOT, params=params)
    if (('ex_private' in kwargs) and kwargs['ex_private']):
        params = {'api_action': 'linode.ip.addprivate', 'LinodeID': linode['id']}
        self.connection.request(API_ROOT, params=params)
    label = {'lconfig': ('[%s]    Configuration    Profile' % linode['id']), 'lroot': ('[%s]    %s    Disk    Image' % (linode['id'], image.name)), 'lswap': ('[%s]    Swap    Space' % linode['id'])}
    for what in ['lconfig', 'lroot', 'lswap']:
        if (what in kwargs):
            label[what] = kwargs[what]
    if (not root):
        root = binascii.b2a_base64(os.urandom(8)).decode('ascii').strip()
    params = {'api_action': 'linode.disk.createfromdistribution', 'LinodeID': linode['id'], 'DistributionID': image.id, 'Label': label['lroot'], 'Size': imagesize, 'rootPass': root}
    if ssh:
        params['rootSSHKey'] = ssh
    data = self.connection.request(API_ROOT, params=params).objects[0]
    linode['rootimage'] = data['DiskID']
    params = {'api_action': 'linode.disk.create', 'LinodeID': linode['id'], 'Label': label['lswap'], 'Type': 'swap', 'Size': swap}
    data = self.connection.request(API_ROOT, params=params).objects[0]
    linode['swapimage'] = data['DiskID']
    disks = ('%s,%s,,,,,,,' % (linode['rootimage'], linode['swapimage']))
    params = {'api_action': 'linode.config.create', 'LinodeID': linode['id'], 'KernelID': kernel, 'Label': label['lconfig'], 'Comments': comments, 'DiskList': disks}
    if (('ex_private' in kwargs) and kwargs['ex_private']):
        params['helper_network'] = True
        params['helper_distro'] = True
    data = self.connection.request(API_ROOT, params=params).objects[0]
    linode['config'] = data['ConfigID']
    params = {'api_action': 'linode.boot', 'LinodeID': linode['id'], 'ConfigID': linode['config']}
    self.connection.request(API_ROOT, params=params)
    params = {'api_action': 'linode.list', 'LinodeID': linode['id']}
    data = self.connection.request(API_ROOT, params=params).objects[0]
    nodes = self._to_nodes(data)
    if (len(nodes) == 1):
        node = nodes[0]
        if getattr(auth, 'generated', False):
            node.extra['password'] = auth.password
        return node
    return None
