def create(nova_client, neutron_client, **kwargs):
    ctx.logger.info('Create: runtime_properties are: %s', ctx.instance.runtime_properties)
    orig_nova_plugin_server.create(nova_client, neutron_client, **kwargs)

    ctx.logger.info("Creating floating IP")

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties['floatingip'])

    # Sugar: floating_network_name -> (resolve) -> floating_network_id
    if 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif 'floating_network_id' not in floatingip:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
    else:
        raise NonRecoverableError('Missing floating network id or name')

    fip = neutron_client.create_floatingip(
        {'floatingip': floatingip})['floatingip']
    ctx.logger.info('Floating IP creation response: {0}'.format(fip))

    ctx.instance.runtime_properties['msw_floating_ip'] = fip['floating_ip_address']
    ctx.instance.runtime_properties['msw_floating_ip_id'] = fip['id']
    ctx.logger.info('Create: runtime_properties are now: %s', ctx.instance.runtime_properties)
def create(neutron_client, args, **kwargs):

    if use_external_floatingip(neutron_client, 'floating_ip_address',
                               lambda ext_fip: ext_fip['floating_ip_address']):
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties['floatingip'], **args)

    # Sugar: floating_network_name -> (resolve) -> floating_network_id
    if 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif 'floating_network_id' not in floatingip:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
    else:
        raise NonRecoverableError('Missing floating network id or name')

    fip = neutron_client.create_floatingip(
        {'floatingip': floatingip})['floatingip']
    set_floatingip_runtime_properties(fip['id'], fip['floating_ip_address'])

    ctx.logger.info('Floating IP creation response: {0}'.format(fip))
def create(neutron_client, **kwargs):

    external_fip = use_external_resource(
        ctx, neutron_client, FLOATINGIP_OPENSTACK_TYPE, 'floating_ip_address')
    if external_fip:
        ctx.instance.runtime_properties[IP_ADDRESS_PROPERTY] = \
            external_fip['floating_ip_address']
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties['floatingip'])

    # Sugar: floating_network_name -> (resolve) -> floating_network_id
    if 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif 'floating_network_id' not in floatingip:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
    else:
        raise NonRecoverableError('Missing floating network id or name')

    fip = neutron_client.create_floatingip(
        {'floatingip': floatingip})['floatingip']
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = fip['id']
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        FLOATINGIP_OPENSTACK_TYPE
    ctx.instance.runtime_properties[IP_ADDRESS_PROPERTY] = \
        fip['floating_ip_address']
def create(neutron_client, **kwargs):

    if use_external_floatingip(neutron_client, 'floating_ip_address',
                               lambda ext_fip: ext_fip['floating_ip_address']):
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties['floatingip'])

    # Sugar: floating_network_name -> (resolve) -> floating_network_id
    if 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif 'floating_network_id' not in floatingip:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
    else:
        raise NonRecoverableError('Missing floating network id or name')

    fip = neutron_client.create_floatingip({'floatingip':
                                            floatingip})['floatingip']
    set_floatingip_runtime_properties(fip['id'], fip['floating_ip_address'])

    ctx.logger.info('Floating IP creation response: {0}'.format(fip))
def create(neutron_client, args, **kwargs):

    if use_external_floatingip(neutron_client, 'floating_ip_address',
                               lambda ext_fip: ext_fip['floating_ip_address']):
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties[FLOATINGIP_OPENSTACK_TYPE], **args)

    # Do we have a relationship with a network?

    connected_network = \
        get_single_connected_node_by_openstack_type(
            ctx, NETWORK_OPENSTACK_TYPE, True)

    if connected_network:
        network_from_rel = connected_network.runtime_properties[
            OPENSTACK_ID_PROPERTY]
    else:
        network_from_rel = None

    # TODO: Should we check whether this is really an "external" network?

    network_name_provided = 'floating_network_name' in floatingip
    network_id_provided = 'floating_network_id' in floatingip
    provided = [
        network_name_provided, network_id_provided, network_from_rel
        is not None
    ].count(True)

    # At most one is expected.

    if provided > 1:
        raise NonRecoverableError(
            FLOATING_NETWORK_ERROR_MSG.format(network_from_rel, floatingip))

    if network_from_rel:
        floatingip['floating_network_id'] = network_from_rel
    elif network_name_provided:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif not network_id_provided:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
        else:
            raise NonRecoverableError(
                FLOATING_NETWORK_ERROR_MSG.format(None, None))

    fip = neutron_client.create_floatingip(
        {FLOATINGIP_OPENSTACK_TYPE: floatingip})[FLOATINGIP_OPENSTACK_TYPE]
    set_floatingip_runtime_properties(fip['id'], fip['floating_ip_address'])

    ctx.logger.info('Floating IP creation response: {0}'.format(fip))
def create(ctx, neutron_client, **kwargs):
    """ Create a router.
    Optional relationship is to gateway network.
    Also supports `router.external_gateway_info.network_name`,
    which is translated to `router.external_gateway_info.network_id`.
    """

    network_id_set = False

    provider_context = provider(ctx)

    ctx.logger.debug('router.create(): kwargs={0}'.format(kwargs))
    router = {
        'name': ctx.node_id,
    }
    router.update(ctx.properties['router'])
    transform_resource_name(router, ctx)

    # Probably will not be used. External network
    # is usually provisioned externally.
    if 'external_id' in ctx.capabilities:
        if 'external_gateway_info' not in router:
            router['external_gateway_info'] = {
                'enable_snat': True
            }
        router['external_gateway_info'][
            'network_id'] = ctx.capabilities['external_id']
        network_id_set = True

    # Sugar: external_gateway_info.network_name ->
    # external_gateway_info.network_id

    if 'external_gateway_info' in router:
        egi = router['external_gateway_info']
        if 'network_name' in egi:
            egi['network_id'] = neutron_client.cosmo_get_named(
                'network', egi['network_name'])['id']
            del egi['network_name']
            network_id_set = True

    if not network_id_set:
        router['external_gateway_info'] = router.get('external_gateway_info',
                                                     {})
        ext_network = provider_context.ext_network
        if ext_network:
            router['external_gateway_info']['network_id'] = ext_network['id']
            network_id_set = True

    if not network_id_set:
        raise NonRecoverableError('Missing network name or network')

    r = neutron_client.create_router({'router': router})['router']

    ctx.runtime_properties['external_id'] = r['id']
def create(neutron_client, **kwargs):

    # Already acquired?
    if ctx.runtime_properties.get(OPENSTACK_ID_PROPERTY):
        ctx.logger.debug("Using already allocated Floating IP {0}".format(
            ctx.runtime_properties[IP_ADDRESS_PROPERTY]))
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.properties['floatingip'])

    # Sugar: ip -> (copy as is) -> floating_ip_address
    if 'ip' in floatingip:
        floatingip['floating_ip_address'] = floatingip['ip']
        del floatingip['ip']

    if 'floating_ip_address' in floatingip:
        fip = neutron_client.cosmo_get(
            'floatingip',
            floating_ip_address=floatingip['floating_ip_address'])
        ctx.runtime_properties[OPENSTACK_ID_PROPERTY] = fip['id']
        ctx.runtime_properties[IP_ADDRESS_PROPERTY] = \
            fip['floating_ip_address']
        ctx.runtime_properties[ENABLE_DELETION_PROPERTY] = \
            False  # Not acquired here
        return

    # Sugar: floating_network_name -> (resolve) -> floating_network_id
    if 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        del floatingip['floating_network_name']
    elif 'floating_network_id' not in floatingip:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
    else:
        raise NonRecoverableError('Missing floating network id or name')

    fip = neutron_client.create_floatingip(
        {'floatingip': floatingip})['floatingip']
    ctx.runtime_properties[OPENSTACK_ID_PROPERTY] = fip['id']
    ctx.runtime_properties[IP_ADDRESS_PROPERTY] = fip['floating_ip_address']
    # Acquired here -> OK to delete
    ctx.runtime_properties[ENABLE_DELETION_PROPERTY] = True
    ctx.logger.info(
        "Allocated floating IP {0}".format(fip['floating_ip_address']))
def _handle_external_network_config(router, neutron_client):
    # attempting to find an external network for the router to connect to -
    # first by either a network name or id passed in explicitly; then by a
    # network connected by a relationship; with a final optional fallback to an
    # external network set in the Provider-context. Otherwise the router will
    # simply not get connected to an external network

    provider_context = provider(ctx)

    ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client)
    ext_net_by_property = ctx.node.properties['external_network']

    # the following is meant for backwards compatibility with the
    # 'network_name' sugaring
    if 'external_gateway_info' in router and 'network_name' in \
            router['external_gateway_info']:
        warnings.warn(
            'Passing external "network_name" inside the '
            'external_gateway_info key of the "router" property is now '
            'deprecated; Use the "external_network" property instead',
            DeprecationWarning)

        ext_net_by_property = router['external_gateway_info']['network_name']
        del (router['external_gateway_info']['network_name'])

    # need to check if the user explicitly passed network_id in the external
    # gateway configuration as it affects external network behavior by
    # relationship and/or provider context
    if 'external_gateway_info' in router and 'network_id' in \
            router['external_gateway_info']:
        ext_net_by_property = \
            router['external_gateway_info'].get('network_name')

    if ext_net_by_property and ext_net_id_by_rel:
        raise RuntimeError(
            "Router can't have an external network connected by both a "
            'relationship and by a network name/id')

    if ext_net_by_property:
        ext_net_id = get_resource_by_name_or_id(ext_net_by_property,
                                                NETWORK_OPENSTACK_TYPE,
                                                neutron_client)['id']
        _insert_ext_net_id_to_router_config(ext_net_id, router)
    elif ext_net_id_by_rel:
        _insert_ext_net_id_to_router_config(ext_net_id_by_rel, router)
    elif ctx.node.properties['default_to_managers_external_network'] and \
            provider_context.ext_network:
        _insert_ext_net_id_to_router_config(provider_context.ext_network['id'],
                                            router)
Exemple #9
0
def create(neutron_client, args, **kwargs):

    if use_external_floatingip(neutron_client, 'floating_ip_address',
                               lambda ext_fip: ext_fip['floating_ip_address']):
        return

    floatingip = {
        # No defaults
    }
    floatingip.update(ctx.node.properties[FLOATINGIP_OPENSTACK_TYPE], **args)

    network_from_rel = \
        get_openstack_id_of_single_connected_node_by_openstack_type(
            ctx, NETWORK_OPENSTACK_TYPE, True)

    if 'floating_network_id' in floatingip:
        ctx.logger.debug('Using floating ip network {0}.'.format(
            floatingip['floating_network_id']))
    elif 'floating_network_name' in floatingip:
        floatingip['floating_network_id'] = neutron_client.cosmo_get_named(
            'network', floatingip['floating_network_name'])['id']
        ctx.logger.debug(
            'Using floating ip network {0} from name {1} provided.'.format(
                floatingip['floating_network_id'],
                floatingip['floating_network_name']))
        del floatingip['floating_network_name']
    elif network_from_rel:
        floatingip['floating_network_id'] = network_from_rel
        ctx.logger.debug(
            'Using floating ip network {0} from relationship.'.format(
                floatingip['floating_network_id']))
    else:
        provider_context = provider(ctx)
        ext_network = provider_context.ext_network
        if ext_network:
            floatingip['floating_network_id'] = ext_network['id']
            ctx.logger.debug(
                'Using floating ip network {0} from provider context.'.format(
                    floatingip['floating_network_id']))
        else:
            raise NonRecoverableError(
                FLOATING_NETWORK_ERROR_MSG.format(None, None))

    fip = neutron_client.create_floatingip(
        {FLOATINGIP_OPENSTACK_TYPE: floatingip})[FLOATINGIP_OPENSTACK_TYPE]
    set_floatingip_runtime_properties(fip['id'], fip['floating_ip_address'])

    ctx.logger.info('Floating IP creation response: {0}'.format(fip))
def _handle_external_network_config(router, neutron_client):
    # attempting to find an external network for the router to connect to -
    # first by either a network name or id passed in explicitly; then by a
    # network connected by a relationship; with a final optional fallback to an
    # external network set in the Provider-context. Otherwise the router will
    # simply not get connected to an external network

    provider_context = provider(ctx)

    ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client)
    ext_net_by_property = ctx.node.properties['external_network']

    # the following is meant for backwards compatibility with the
    # 'network_name' sugaring
    if 'external_gateway_info' in router and 'network_name' in \
            router['external_gateway_info']:
        warnings.warn(
            'Passing external "network_name" inside the '
            'external_gateway_info key of the "router" property is now '
            'deprecated; Use the "external_network" property instead',
            DeprecationWarning)

        ext_net_by_property = router['external_gateway_info']['network_name']
        del (router['external_gateway_info']['network_name'])

    # need to check if the user explicitly passed network_id in the external
    # gateway configuration as it affects external network behavior by
    # relationship and/or provider context
    if 'external_gateway_info' in router and 'network_id' in \
            router['external_gateway_info']:
        ext_net_by_property = \
            router['external_gateway_info'].get('network_name')

    if ext_net_by_property and ext_net_id_by_rel:
        raise RuntimeError(
            "Router can't have an external network connected by both a "
            'relationship and by a network name/id')

    if ext_net_by_property:
        ext_net_id = get_resource_by_name_or_id(
            ext_net_by_property, NETWORK_OPENSTACK_TYPE, neutron_client)['id']
        _insert_ext_net_id_to_router_config(ext_net_id, router)
    elif ext_net_id_by_rel:
        _insert_ext_net_id_to_router_config(ext_net_id_by_rel, router)
    elif ctx.node.properties['default_to_managers_external_network'] and \
            provider_context.ext_network:
        _insert_ext_net_id_to_router_config(provider_context.ext_network['id'],
                                            router)
Exemple #11
0
def _get_management_network_id_and_name(neutron_client, ctx):
    """Examine the context to find the management network id and name."""
    management_network_id = None
    management_network_name = \
        ctx.node.properties.get('management_network_name')
    provider_context = provider(ctx)

    if management_network_name:
        management_network_name = transform_resource_name(
            ctx, management_network_name)
        management_network_id = neutron_client.cosmo_get_named(
            'network', management_network_name)
        management_network_id = management_network_id['id']
    else:
        int_network = provider_context.int_network
        if int_network:
            management_network_id = int_network['id']
            management_network_name = int_network['name']  # Already transform.

    return management_network_id, management_network_name
def _get_management_network_id_and_name(neutron_client, ctx):
    """Examine the context to find the management network id and name."""
    management_network_id = None
    management_network_name = \
        ctx.node.properties.get('management_network_name')
    provider_context = provider(ctx)

    if management_network_name:
        management_network_name = transform_resource_name(
            ctx, management_network_name)
        management_network_id = neutron_client.cosmo_get_named(
            'network', management_network_name)
        management_network_id = management_network_id['id']
    else:
        int_network = provider_context.int_network
        if int_network:
            management_network_id = int_network['id']
            management_network_name = int_network['name']  # Already transform.

    return management_network_id, management_network_name
Exemple #13
0
def create(nova_client, neutron_client, args, **kwargs):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    """

    external_server = use_external_resource(ctx, nova_client,
                                            SERVER_OPENSTACK_TYPE)

    if external_server:
        _set_network_and_ip_runtime_properties(external_server)
        if ctx._local:
            return
        else:
            network_ids = \
                get_openstack_ids_of_connected_nodes_by_openstack_type(
                    ctx, NETWORK_OPENSTACK_TYPE)
            port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
                ctx, PORT_OPENSTACK_TYPE)
            try:
                _validate_external_server_nics(
                    neutron_client,
                    network_ids,
                    port_ids
                )
                _validate_external_server_keypair(nova_client)
                return
            except Exception:
                delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
                raise

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(ctx, name)

    server = {
        'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE),
    }
    server.update(copy.deepcopy(ctx.node.properties['server']))
    server.update(copy.deepcopy(args))

    _handle_boot_volume(server, ctx)
    handle_image_from_relationship(server, 'image', ctx)

    if 'meta' not in server:
        server['meta'] = dict()

    transform_resource_name(ctx, server)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    if ('block_device_mapping' in server or
            'block_device_mapping_v2' in server) \
            and 'image' not in server:
        # python-novaclient requires an image field even if BDM is used.
        server['image'] = ctx.node.properties.get('image')
    else:
        _handle_image_or_flavor(server, nova_client, 'image')
    _handle_image_or_flavor(server, nova_client, 'flavor')

    if provider_context.agents_security_group:
        security_groups = server.get('security_groups', [])
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
        server['security_groups'] = security_groups
    elif not server.get('security_groups', []):
        # Make sure that if the server is connected to a security group
        # from CREATE time so that there the user can control
        # that there is never a time that a running server is not protected.
        security_group_names = \
            get_openstack_names_of_connected_nodes_by_openstack_type(
                ctx,
                SECURITY_GROUP_OPENSTACK_TYPE)
        server['security_groups'] = security_group_names

    # server keypair handling
    keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, KEYPAIR_OPENSTACK_TYPE, True)

    if 'key_name' in server:
        if keypair_id:
            raise NonRecoverableError("server can't both have the "
                                      '"key_name" nested property and be '
                                      'connected to a keypair via a '
                                      'relationship at the same time')
        server['key_name'] = rename(server['key_name'])
    elif keypair_id:
        server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id)
    elif provider_context.agents_keypair:
        server['key_name'] = provider_context.agents_keypair['name']
    else:
        server['key_name'] = None
        ctx.logger.info(
            'server must have a keypair, yet no keypair was connected to the '
            'server node, the "key_name" nested property '
            "wasn't used, and there is no agent keypair in the provider "
            "context. Agent installation can have issues.")

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor'),
        'server')

    _prepare_server_nics(neutron_client, ctx, server)

    # server group handling
    server_group_id = \
        get_openstack_id_of_single_connected_node_by_openstack_type(
            ctx, SERVER_GROUP_OPENSTACK_TYPE, True)
    if server_group_id:
        scheduler_hints = server.get('scheduler_hints', {})
        scheduler_hints['group'] = server_group_id
        server['scheduler_hints'] = scheduler_hints

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    userdata.handle_userdata(server)

    ctx.logger.info("Creating VM with parameters: {0}".format(str(server)))
    # Store the server dictionary contents in runtime properties
    assign_payload_as_runtime_properties(ctx, SERVER_OPENSTACK_TYPE, server)
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: [{0}]"
        .format(','.join(server.keys())))

    try:
        s = nova_client.servers.create(**server)
    except nova_exceptions.BadRequest as e:
        if 'Block Device Mapping is Invalid' in str(e):
            return ctx.operation.retry(
                message='Block Device Mapping is not created yet',
                retry_after=30)
        raise
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        SERVER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name']
def create(nova_client, neutron_client, **kwargs):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    Userdata:

    In all cases, note that userdata should not be base64 encoded,
    novaclient expects it raw.
    The 'userdata' argument under nova.instance can be one of
    the following:

    - A string
    - A hash with 'type: http' and 'url: ...'
    """

    network_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, NETWORK_OPENSTACK_TYPE)
    port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, PORT_OPENSTACK_TYPE)

    external_server = use_external_resource(ctx, nova_client,
                                            SERVER_OPENSTACK_TYPE)
    if external_server:
        try:
            _validate_external_server_nics(network_ids, port_ids)
            _validate_external_server_keypair(nova_client)
            _set_network_and_ip_runtime_properties(external_server)
            return
        except Exception:
            delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
            raise

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(ctx, name)

    # For possible changes by _maybe_transform_userdata()

    server = {
        'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE),
    }
    server.update(copy.deepcopy(ctx.node.properties['server']))
    transform_resource_name(ctx, server)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    _maybe_transform_userdata(server)

    management_network_id = None
    management_network_name = None

    if ('management_network_name' in ctx.node.properties) and \
            ctx.node.properties['management_network_name']:
        management_network_name = \
            ctx.node.properties['management_network_name']
        management_network_name = rename(management_network_name)
        nc = _neutron_client()
        management_network_id = nc.cosmo_get_named(
            'network', management_network_name)['id']
    else:
        int_network = provider_context.int_network
        if int_network:
            management_network_id = int_network['id']
            management_network_name = int_network['name']  # Already transform.
    if management_network_id is not None:
        server['nics'] = \
            server.get('nics', []) + [{'net-id': management_network_id}]

    _handle_image_or_flavor(server, nova_client, 'image')
    _handle_image_or_flavor(server, nova_client, 'flavor')

    if provider_context.agents_security_group:
        security_groups = server.get('security_groups', [])
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
        server['security_groups'] = security_groups

    # server keypair handling
    keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, KEYPAIR_OPENSTACK_TYPE, True)

    if 'key_name' in server:
        if keypair_id:
            raise NonRecoverableError("server can't both have the "
                                      '"key_name" nested property and be '
                                      'connected to a keypair via a '
                                      'relationship at the same time')
        server['key_name'] = rename(server['key_name'])
    elif keypair_id:
        server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id)
    elif provider_context.agents_keypair:
        server['key_name'] = provider_context.agents_keypair['name']
    else:
        raise NonRecoverableError(
            'server must have a keypair, yet no keypair was connected to the '
            'server node, the "key_name" nested property'
            "wasn't used, and there is no agent keypair in the provider "
            "context")

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor', 'image', 'key_name'),
        'server')

    if management_network_id is None and (network_ids or port_ids):
        # Known limitation
        raise NonRecoverableError(
            "Nova server with NICs requires "
            "'management_network_name' in properties or id "
            "from provider context, which was not supplied")

    # Multi-NIC by networks - start
    nics = [{'net-id': net_id} for net_id in network_ids]
    if nics:
        if management_network_id in network_ids:
            # de-duplicating the management network id in case it appears in
            # network_ids. There has to be a management network if a
            # network is connected to the server.
            # note: if the management network appears more than once in
            # network_ids it won't get de-duplicated and the server creation
            # will fail.
            nics.remove({'net-id': management_network_id})

        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by networks - end

    # Multi-NIC by ports - start
    nics = [{'port-id': port_id} for port_id in port_ids]
    if nics:
        port_network_ids = get_port_network_ids_(neutron_client, port_ids)
        if management_network_id in port_network_ids:
            # de-duplicating the management network id in case it appears in
            # port_ids. There has to be a management network if a
            # network is connected to the server.
            # note: if the management network appears more than once in
            # network_ids it won't get de-duplicated and the server creation
            # will fail.
            server['nics'].remove({'net-id': management_network_id})

        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by ports - end

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    # First parameter is 'self', skipping
    params_names = inspect.getargspec(nova_client.servers.create).args[1:]

    params_default_values = inspect.getargspec(
        nova_client.servers.create).defaults
    params = dict(itertools.izip(params_names, params_default_values))

    # Fail on unsupported parameters
    for k in server:
        if k not in params:
            raise NonRecoverableError(
                "Parameter with name '{0}' must not be passed to"
                " openstack provisioner (under host's "
                "properties.nova.instance)".format(k))

    for k in params:
        if k in server:
            params[k] = server[k]

    if not params['meta']:
        params['meta'] = dict({})
    if management_network_id is not None:
        params['meta']['cloudify_management_network_id'] = \
            management_network_id
    if management_network_name is not None:
        params['meta']['cloudify_management_network_name'] = \
            management_network_name

    ctx.logger.info("Creating VM with parameters: {0}".format(str(params)))
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: {0})"
        .format(','.join(params.keys())))

    try:
        s = nova_client.servers.create(**params)
    except nova_exceptions.BadRequest as e:
        if str(e).startswith(MUST_SPECIFY_NETWORK_EXCEPTION_TEXT):
            raise NonRecoverableError(
                "Can not provision server: management_network_name or id"
                " is not specified but there are several networks that the "
                "server can be connected to.")
        raise
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        SERVER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name']
def create(nova_client, neutron_client, args, **kwargs):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    """

    external_server = use_external_resource(ctx, nova_client,
                                            SERVER_OPENSTACK_TYPE)

    if external_server:
        _set_network_and_ip_runtime_properties(external_server)
        if ctx._local:
            return
        else:
            network_ids = \
                get_openstack_ids_of_connected_nodes_by_openstack_type(
                    ctx, NETWORK_OPENSTACK_TYPE)
            port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
                ctx, PORT_OPENSTACK_TYPE)
            try:
                _validate_external_server_nics(
                    neutron_client,
                    network_ids,
                    port_ids
                )
                _validate_external_server_keypair(nova_client)
                return
            except Exception:
                delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
                raise

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(ctx, name)

    server = {
        'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE),
    }
    server.update(copy.deepcopy(ctx.node.properties['server']))
    server.update(copy.deepcopy(args))

    _handle_boot_volume(server, ctx)
    handle_image_from_relationship(server, 'image', ctx)

    if 'meta' not in server:
        server['meta'] = dict()

    transform_resource_name(ctx, server)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    if ('block_device_mapping' in server or
            'block_device_mapping_v2' in server) \
            and 'image' not in server:
        # python-novaclient requires an image field even if BDM is used.
        server['image'] = ctx.node.properties.get('image')
    else:
        _handle_image_or_flavor(server, nova_client, 'image')
    _handle_image_or_flavor(server, nova_client, 'flavor')

    if provider_context.agents_security_group:
        security_groups = server.get('security_groups', [])
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
        server['security_groups'] = security_groups
    elif not server.get('security_groups', []):
        # Make sure that if the server is connected to a security group
        # from CREATE time so that there the user can control
        # that there is never a time that a running server is not protected.
        security_group_names = \
            get_openstack_names_of_connected_nodes_by_openstack_type(
                ctx,
                SECURITY_GROUP_OPENSTACK_TYPE)
        server['security_groups'] = security_group_names

    # server keypair handling
    keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, KEYPAIR_OPENSTACK_TYPE, True)

    if 'key_name' in server:
        if keypair_id:
            raise NonRecoverableError("server can't both have the "
                                      '"key_name" nested property and be '
                                      'connected to a keypair via a '
                                      'relationship at the same time')
        server['key_name'] = rename(server['key_name'])
    elif keypair_id:
        server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id)
    elif provider_context.agents_keypair:
        server['key_name'] = provider_context.agents_keypair['name']
    else:
        server['key_name'] = None
        ctx.logger.info(
            'server must have a keypair, yet no keypair was connected to the '
            'server node, the "key_name" nested property '
            "wasn't used, and there is no agent keypair in the provider "
            "context. Agent installation can have issues.")

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor'),
        'server')

    _prepare_server_nics(neutron_client, ctx, server)

    # server group handling
    server_group_id = \
        get_openstack_id_of_single_connected_node_by_openstack_type(
            ctx, SERVER_GROUP_OPENSTACK_TYPE, True)
    if server_group_id:
        scheduler_hints = server.get('scheduler_hints', {})
        scheduler_hints['group'] = server_group_id
        server['scheduler_hints'] = scheduler_hints

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    userdata.handle_userdata(server)

    ctx.logger.info("Creating VM with parameters: {0}".format(str(server)))
    # Store the server dictionary contents in runtime properties
    assign_payload_as_runtime_properties(ctx, SERVER_OPENSTACK_TYPE, server)
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: {0})"
        .format(','.join(server.keys())))

    try:
        s = nova_client.servers.create(**server)
    except nova_exceptions.BadRequest as e:
        if 'Block Device Mapping is Invalid' in str(e):
            return ctx.operation.retry(
                message='Block Device Mapping is not created yet',
                retry_after=30)
        raise
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        SERVER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name']
def create(neutron_client, **kwargs):
    """Create a router.
    Optional relationship is to gateway network.
    Also supports `router.external_gateway_info.network_name`,
    which is translated to `router.external_gateway_info.network_id`.
    """

    if use_external_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE):
        return

    network_id_set = False

    provider_context = provider(ctx)

    ctx.logger.debug('router.create(): kwargs={0}'.format(kwargs))
    router = {
        'name': get_resource_id(ctx, ROUTER_OPENSTACK_TYPE),
    }
    router.update(ctx.node.properties['router'])
    transform_resource_name(ctx, router)

    # Probably will not be used. External network
    # is usually provisioned externally.
    # TODO: remove this or modify - it's unreasonable to look for
    # OPENSTACK_ID_PROPERTY in capabilities as it can be of any connected
    # node. If the usage of capabilities here remains, need to add
    # validation in the 'use_external_resource' (before returning) that the
    # network used is the one connected to the router.
    if OPENSTACK_ID_PROPERTY in ctx.capabilities:
        if 'external_gateway_info' not in router:
            router['external_gateway_info'] = {
                'enable_snat': True
            }
        router['external_gateway_info'][
            'network_id'] = ctx.capabilities[OPENSTACK_ID_PROPERTY]
        network_id_set = True

    # Sugar: external_gateway_info.network_name ->
    # external_gateway_info.network_id

    if 'external_gateway_info' in router:
        egi = router['external_gateway_info']
        if 'network_name' in egi:
            egi['network_id'] = neutron_client.cosmo_get_named(
                'network', egi['network_name'])['id']
            del egi['network_name']
            network_id_set = True

    if not network_id_set:
        router['external_gateway_info'] = router.get('external_gateway_info',
                                                     {})
        ext_network = provider_context.ext_network
        if ext_network:
            router['external_gateway_info']['network_id'] = ext_network['id']
            network_id_set = True

    if not network_id_set:
        raise NonRecoverableError('Missing network name or network')

    r = neutron_client.create_router({'router': router})['router']

    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = r['id']
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] =\
        ROUTER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = r['name']
def start_new_server(ctx, nova_client):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    Userdata:

    In all cases, note that userdata should not be base64 encoded,
    novaclient expects it raw.
    The 'userdata' argument under nova.instance can be one of
    the following:

    - A string
    - A hash with 'type: http' and 'url: ...'
    """

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(name, ctx)

    # For possible changes by _maybe_transform_userdata()

    server = {
        'name': ctx.node_id
    }
    server.update(copy.deepcopy(ctx.properties['server']))
    transform_resource_name(server, ctx)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    if 'nics' in server:
        raise NonRecoverableError(
            "Parameter with name 'nics' must not be passed to"
            " openstack provisioner (under host's "
            "properties.nova.instance)")

    _maybe_transform_userdata(server)

    management_network_id = None
    management_network_name = None
    nc = None

    if ('management_network_name' in ctx.properties) and \
            ctx.properties['management_network_name']:
        management_network_name = ctx.properties['management_network_name']
        management_network_name = rename(management_network_name)
        nc = _neutron_client(ctx)
        management_network_id = nc.cosmo_get_named(
            'network', management_network_name)['id']
    else:

        int_network = provider_context.int_network
        if int_network:
            management_network_id = int_network['id']
            management_network_name = int_network['name']  # Already transform.
    if management_network_id is not None:
        nc = _neutron_client(ctx)
        server['nics'] = [{'net-id': management_network_id}]

    # Sugar
    if 'image_name' in server:
        server['image'] = nova_client.images.find(
            name=server['image_name']).id
        del server['image_name']
    if 'flavor_name' in server:
        server['flavor'] = nova_client.flavors.find(
            name=server['flavor_name']).id
        del server['flavor_name']

    security_groups = map(rename, server.get('security_groups', []))
    if provider_context.agents_security_group:
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
    server['security_groups'] = security_groups

    if 'key_name' in server:
        server['key_name'] = rename(server['key_name'])
    else:
        # 'key_name' not in server
        if provider_context.agents_keypair:
            server['key_name'] = provider_context.agents_keypair['name']

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor', 'image', 'key_name'),
        'server')

    # Multi-NIC by networks - start
    network_nodes_runtime_properties = ctx.capabilities.get_all().values()
    if network_nodes_runtime_properties and \
            management_network_id is None:
        # Known limitation
        raise NonRecoverableError(
            "Nova server with multi-NIC requires "
            "'management_network_name' in properties  or id "
            "from provider context, which was not supplied")
    nics = [
        {'net-id': n['external_id']}
        for n in network_nodes_runtime_properties
        if nc.cosmo_is_network(n['external_id'])
    ]
    if nics:
        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by networks - end

    # Multi-NIC by ports - start
    port_nodes_runtime_properties = ctx.capabilities.get_all().values()
    if port_nodes_runtime_properties and \
            management_network_id is None:
        # Known limitation
        raise NonRecoverableError(
            "Nova server with multi-NIC requires "
            "'management_network_name' in properties  or id "
            "from provider context, which was not supplied")
    nics = [
        {'port-id': n['external_id']}
        for n in port_nodes_runtime_properties
        if nc.cosmo_is_port(n['external_id'])
    ]
    if nics:
        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by ports - end

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    # First parameter is 'self', skipping
    params_names = inspect.getargspec(nova_client.servers.create).args[1:]

    params_default_values = inspect.getargspec(
        nova_client.servers.create).defaults
    params = dict(itertools.izip(params_names, params_default_values))

    # Fail on unsupported parameters
    for k in server:
        if k not in params:
            raise NonRecoverableError(
                "Parameter with name '{0}' must not be passed to"
                " openstack provisioner (under host's "
                "properties.nova.instance)".format(k))

    for k in params:
        if k in server:
            params[k] = server[k]

    if not params['meta']:
        params['meta'] = dict({})
    params['meta'][NODE_ID_PROPERTY] = ctx.node_id
    if management_network_id is not None:
        params['meta']['cloudify_management_network_id'] = \
            management_network_id
    if management_network_name is not None:
        params['meta']['cloudify_management_network_name'] = \
            management_network_name

    ctx.logger.info("Creating VM with parameters: {0}".format(str(params)))
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: {0})"
        .format(','.join(params.keys())))

    try:
        s = nova_client.servers.create(**params)
    except nova_exceptions.BadRequest as e:
        if str(e).startswith(MUST_SPECIFY_NETWORK_EXCEPTION_TEXT):
            raise NonRecoverableError(
                "Can not provision server: management_network_name or id"
                " is not specified but there are several networks that the "
                "server can be connected to."
            )
        raise NonRecoverableError("Nova bad request error: " + str(e))
    except nova_exceptions.ClientException as e:
        raise NonRecoverableError("Nova client error: " + str(e))
    ctx.runtime_properties[OPENSTACK_SERVER_ID_PROPERTY] = s.id
Exemple #18
0
def create(nova_client, neutron_client, args, **kwargs):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    """

    network_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, NETWORK_OPENSTACK_TYPE)
    port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, PORT_OPENSTACK_TYPE)

    external_server = use_external_resource(ctx, nova_client,
                                            SERVER_OPENSTACK_TYPE)
    if external_server:
        try:
            _validate_external_server_nics(
                neutron_client,
                network_ids,
                port_ids
            )
            _validate_external_server_keypair(nova_client)
            _set_network_and_ip_runtime_properties(external_server)
            return
        except Exception:
            delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
            raise

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(ctx, name)

    server = {
        'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE),
    }
    server.update(copy.deepcopy(ctx.node.properties['server']))
    server.update(copy.deepcopy(args))
    transform_resource_name(ctx, server)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    management_network_id = None
    management_network_name = None

    if ('management_network_name' in ctx.node.properties) and \
            ctx.node.properties['management_network_name']:
        management_network_name = \
            ctx.node.properties['management_network_name']
        management_network_name = rename(management_network_name)
        management_network_id = neutron_client.cosmo_get_named(
            'network', management_network_name)['id']
    else:
        int_network = provider_context.int_network
        if int_network:
            management_network_id = int_network['id']
            management_network_name = int_network['name']  # Already transform.
    if management_network_id is not None:
        server['nics'] = \
            server.get('nics', []) + [{'net-id': management_network_id}]

    _handle_image_or_flavor(server, nova_client, 'image')
    _handle_image_or_flavor(server, nova_client, 'flavor')

    if provider_context.agents_security_group:
        security_groups = server.get('security_groups', [])
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
        server['security_groups'] = security_groups

    # server keypair handling
    keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, KEYPAIR_OPENSTACK_TYPE, True)

    if 'key_name' in server:
        if keypair_id:
            raise NonRecoverableError("server can't both have the "
                                      '"key_name" nested property and be '
                                      'connected to a keypair via a '
                                      'relationship at the same time')
        server['key_name'] = rename(server['key_name'])
    elif keypair_id:
        server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id)
    elif provider_context.agents_keypair:
        server['key_name'] = provider_context.agents_keypair['name']
    else:
        raise NonRecoverableError(
            'server must have a keypair, yet no keypair was connected to the '
            'server node, the "key_name" nested property '
            "wasn't used, and there is no agent keypair in the provider "
            "context")

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor', 'image', 'key_name'),
        'server')

    if management_network_id is None and (network_ids or port_ids):
        # Known limitation
        raise NonRecoverableError(
            "Nova server with NICs requires "
            "'management_network_name' in properties or id "
            "from provider context, which was not supplied")

    # Multi-NIC by networks - start
    nics = [{'net-id': net_id} for net_id in network_ids]
    if nics:
        if management_network_id in network_ids:
            # de-duplicating the management network id in case it appears in
            # network_ids. There has to be a management network if a
            # network is connected to the server.
            # note: if the management network appears more than once in
            # network_ids it won't get de-duplicated and the server creation
            # will fail.
            nics.remove({'net-id': management_network_id})

        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by networks - end

    # Multi-NIC by ports - start
    nics = [{'port-id': port_id} for port_id in port_ids]
    if nics:
        port_network_ids = get_port_network_ids_(neutron_client, port_ids)
        if management_network_id in port_network_ids:
            # de-duplicating the management network id in case it appears in
            # port_ids. There has to be a management network if a
            # network is connected to the server.
            # note: if the management network appears more than once in
            # network_ids it won't get de-duplicated and the server creation
            # will fail.
            server['nics'].remove({'net-id': management_network_id})

        server['nics'] = server.get('nics', []) + nics
    # Multi-NIC by ports - end

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    if 'meta' not in server:
        server['meta'] = dict()
    if management_network_id is not None:
        server['meta']['cloudify_management_network_id'] = \
            management_network_id
    if management_network_name is not None:
        server['meta']['cloudify_management_network_name'] = \
            management_network_name

    userdata.handle_userdata(server)

    ctx.logger.info("Creating VM with parameters: {0}".format(str(server)))
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: {0})"
        .format(','.join(server.keys())))

    try:
        s = nova_client.servers.create(**server)
    except nova_exceptions.BadRequest as e:
        if str(e).startswith(MUST_SPECIFY_NETWORK_EXCEPTION_TEXT):
            raise NonRecoverableError(
                "Can not provision server: management_network_name or id"
                " is not specified but there are several networks that the "
                "server can be connected to.")
        raise
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        SERVER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name']
Exemple #19
0
def create(nova_client, neutron_client, args, **kwargs):
    """
    Creates a server. Exposes the parameters mentioned in
    http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1
    .servers.html#novaclient.v1_1.servers.ServerManager.create
    """
    external_server = use_external_resource(ctx, nova_client,
                                            SERVER_OPENSTACK_TYPE)
    if external_server:
        network_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
            ctx, NETWORK_OPENSTACK_TYPE)
        port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
            ctx, PORT_OPENSTACK_TYPE)
        try:
            _validate_external_server_nics(
                neutron_client,
                network_ids,
                port_ids
            )
            _validate_external_server_keypair(nova_client)
            _set_network_and_ip_runtime_properties(external_server)
            return
        except Exception:
            delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
            raise

    provider_context = provider(ctx)

    def rename(name):
        return transform_resource_name(ctx, name)

    server = {
        'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE),
    }
    server.update(copy.deepcopy(ctx.node.properties['server']))
    server.update(copy.deepcopy(args))

    if 'meta' not in server:
        server['meta'] = dict()

    transform_resource_name(ctx, server)

    ctx.logger.debug(
        "server.create() server before transformations: {0}".format(server))

    _handle_image_or_flavor(server, nova_client, 'image')
    _handle_image_or_flavor(server, nova_client, 'flavor')

    if provider_context.agents_security_group:
        security_groups = server.get('security_groups', [])
        asg = provider_context.agents_security_group['name']
        if asg not in security_groups:
            security_groups.append(asg)
        server['security_groups'] = security_groups

    # server keypair handling
    keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, KEYPAIR_OPENSTACK_TYPE, True)

    if 'key_name' in server:
        if keypair_id:
            raise NonRecoverableError("server can't both have the "
                                      '"key_name" nested property and be '
                                      'connected to a keypair via a '
                                      'relationship at the same time')
        server['key_name'] = rename(server['key_name'])
    elif keypair_id:
        server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id)
    elif provider_context.agents_keypair:
        server['key_name'] = provider_context.agents_keypair['name']
    else:
        raise NonRecoverableError(
            'server must have a keypair, yet no keypair was connected to the '
            'server node, the "key_name" nested property '
            "wasn't used, and there is no agent keypair in the provider "
            "context")

    _fail_on_missing_required_parameters(
        server,
        ('name', 'flavor', 'image', 'key_name'),
        'server')

    _prepare_server_nics(neutron_client, ctx, server)

    ctx.logger.debug(
        "server.create() server after transformations: {0}".format(server))

    userdata.handle_userdata(server)

    ctx.logger.info("Creating VM with parameters: {0}".format(str(server)))
    ctx.logger.debug(
        "Asking Nova to create server. All possible parameters are: {0})"
        .format(','.join(server.keys())))

    try:
        s = nova_client.servers.create(**server)
    except nova_exceptions.BadRequest as e:
        if str(e).startswith(MUST_SPECIFY_NETWORK_EXCEPTION_TEXT):
            raise NonRecoverableError(
                "Can not provision server: management_network_name or id"
                " is not specified but there are several networks that the "
                "server can be connected to.")
        raise
    ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id
    ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
        SERVER_OPENSTACK_TYPE
    ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name']