'Creates a node.
image is optional as long as you pass ram, cores, and disk
to the method. ProfitBricks allows you to adjust compute
resources at a much more granular level.
:param  name: The name for the new node.
:param  type: ``str``
:param  image: The image to create the node with.
:type   image: :class:`NodeImage`
:param  size: Standard configured size offered by
ProfitBricks - containing configuration for the
number of cpu cores, amount of ram and disk size.
:param  size: :class:`NodeSize`
:param  location: The location of the new data center
if one is not supplied.
:type   location: :class:`NodeLocation`
:param  ex_cpu_family: The CPU family to use (AMD_OPTERON, INTEL_XEON)
:type   ex_cpu_family: ``str``
:param  volume: If the volume already exists then pass this in.
:type   volume: :class:`StorageVolume`
:param  ex_datacenter: If you\'ve already created the DC then pass
it in.
:type   ex_datacenter: :class:`Datacenter`
:param  ex_network_interface: Create with a network interface.
:type   ex_network_interface: : ``bool``
:param  ex_internet_access: Configure public Internet access.
:type   ex_internet_access: : ``bool``
:param  ex_exposed_public_ports: Ports to be opened
for the public nic.
:param  ex_exposed_public_ports: ``list`` of ``int``
:param  ex_exposed_private_ports: Ports to be opened
for the private nic.
:param  ex_exposed_private_ports: ``list`` of ``int``
:param  ex_availability_zone: The availability zone.
:type   ex_availability_zone: class: `ProfitBricksAvailabilityZone`
:param  ex_ram: The amount of ram required.
:type   ex_ram: : ``int``
:param  ex_cores: The number of cores required.
:type   ex_cores: ``int``
:param  ex_disk: The amount of disk required.
:type   ex_disk: ``int``
:param  ex_password: The password for the volume.
:type   ex_password: ``str``
:param  ex_ssh_keys: Optional SSH keys for the volume.
:type   ex_ssh_keys: ``list`` of ``str``
:param  ex_bus_type: Volume bus type (VIRTIO, IDE).
:type   ex_bus_type: ``str``
:param  ex_disk_type: Volume disk type (SSD, HDD).
:type   ex_disk_type: ``str``
:return:    Instance of class ``Node``
:rtype:     :class: `Node`'

def create_node(self, name, image=None, size=None, location=None, ex_cpu_family=None, volume=None, ex_datacenter=None, ex_network_interface=True, ex_internet_access=True, ex_exposed_public_ports=[], ex_exposed_private_ports=[22], ex_availability_zone=None, ex_ram=None, ex_cores=None, ex_disk=None, ex_password=None, ex_ssh_keys=None, ex_bus_type=None, ex_disk_type=None, **kwargs):

    '\n                                If    we    have    a    volume    we    can    determine    the    DC\n                                that    it    belongs    to    and    set    accordingly.\n                                '
    if (volume is not None):
        dc_url_pruned = volume.extra['href'].split('/')[:(-2)]
        dc_url = '/'.join((item for item in dc_url_pruned))
        ex_datacenter = self.ex_describe_datacenter(ex_href=dc_url)
    if (not ex_datacenter):
        '\n                                                Determine    location    for    new    DC    by\n                                                getting    the    location    of    the    image.\n                                                '
        if (not location):
            if (image is not None):
                location = self.ex_describe_location(ex_location_id=image.extra['location'])
        '\n                                                Creating    a    Datacenter    for    the    node\n                                                since    one    was    not    provided.\n                                                '
        new_datacenter = self._create_new_datacenter_for_node(name=name, location=location)
        '\n                                                Then    wait    for    the    operation    to    finish,\n                                                assigning    the    full    data    center    on    completion.\n                                                '
        ex_datacenter = self._wait_for_datacenter_state(datacenter=new_datacenter)
    if (not size):
        if (not ex_ram):
            raise ValueError('You    need    to    either    pass    a    NodeSize    or    specify    ex_ram    as    an    extra    parameter.')
        if (not ex_cores):
            raise ValueError('You    need    to    either    pass    a    NodeSize    or    specify    ex_cores    as    an    extra    parameter.')
    '\n                                If    passing    in    an    image    we    need\n                                to    enfore    a    password    or    ssh    keys.\n                                '
    if ((not volume) and (image is not None)):
        if ((ex_password is None) and (ex_ssh_keys is None)):
            raise ValueError('When    creating    a    server    without    a    volume,    you    need    to    specify    either    an    array    of    SSH    keys    or    a    volume    password.')
        if (not size):
            if (not ex_disk):
                raise ValueError('You    need    to    either    pass    a    StorageVolume,    a    NodeSize,    or    specify    ex_disk    as    an    extra    parameter.')
    '\n                                You    can    override    the    suggested    sizes    by    passing    in    unique\n                                values    for    ram,    cores,    and    disk    allowing    you    to    size    it\n                                for    your    specific    use.\n                                '
    if (image is not None):
        if (not ex_disk):
            ex_disk = size.disk
    if (not ex_disk_type):
        ex_disk_type = 'HDD'
    if (not ex_bus_type):
        ex_bus_type = 'VIRTIO'
    if (not ex_ram):
        ex_ram = size.ram
    if (not ex_cores):
        ex_cores = size.extra['cores']
    action = (ex_datacenter.href + '/servers')
    body = {'properties': {'name': name, 'ram': ex_ram, 'cores': ex_cores}, 'entities': {'volumes': {'items': []}}}
    '\n                                If    we    are    using    a    pre-existing    storage    volume.\n                                '
    if (volume is not None):
        body['entities']['volumes']['items'].append({'id': volume.id})
    elif (image is not None):
        new_volume = {'properties': {'size': ex_disk, 'name': (name + '    -    volume'), 'image': image.id, 'type': ex_disk_type, 'bus': ex_bus_type}}
        if (ex_password is not None):
            new_volume['properties']['imagePassword'] = ex_password
        if (ex_ssh_keys is not None):
            new_volume['properties']['sshKeys'] = ex_ssh_keys
        body['entities']['volumes']['items'].append(new_volume)
    if (ex_network_interface is True):
        body['entities']['nics'] = {}
        body['entities']['nics']['items'] = list()
        '\n                                                Get    the    LANs    for    the    data    center    this    node\n                                                will    be    provisioned    at.\n                                                '
        dc_lans = self.ex_list_lans(datacenter=ex_datacenter)
        private_lans = [lan for lan in dc_lans if (lan.is_public is False)]
        private_lan = None
        if private_lans:
            private_lan = private_lans[0]
        if (private_lan is not None):
            private_nic = {'properties': {'name': (name + '    -    private    nic'), 'lan': private_lan.id}, 'entities': {'firewallrules': {'items': []}}}
            for port in ex_exposed_private_ports:
                private_nic['entities']['firewallrules']['items'].append({'properties': {'name': '{name}    -    firewall    rule:{port}'.format(name=name, port=port), 'protocol': 'TCP', 'portRangeStart': port, 'portRangeEnd': port}})
            body['entities']['nics']['items'].append(private_nic)
        if ((ex_internet_access is not None) and (ex_internet_access is True)):
            public_lans = [lan for lan in dc_lans if lan.is_public]
            public_lan = None
            if public_lans:
                public_lan = public_lans[0]
            if (public_lan is not None):
                pub_nic = {'properties': {'name': (name + '    -    public    nic'), 'lan': public_lan.id}, 'entities': {'firewallrules': {'items': []}}}
                for port in ex_exposed_public_ports:
                    pub_nic['entities']['firewallrules']['items'].append({'properties': {'name': '{name}    -    firewall    rule:{port}'.format(name=name, port=port), 'protocol': 'TCP', 'portRangeStart': port, 'portRangeEnd': port}})
                body['entities']['nics']['items'].append(pub_nic)
    if (ex_cpu_family is not None):
        body['properties']['cpuFamily'] = ex_cpu_family
    if (ex_availability_zone is not None):
        body['properties']['availabilityZone'] = ex_availability_zone.name
    response = self.connection.request(action=action, headers={'Content-Type': 'application/json'}, data=body, method='POST', with_full_url=True)
    return self._to_node(response.object, response.headers)
