def _prepare_server_nics(neutron_client, ctx, server):
    """Update server['nics'] based on declared relationships.

    server['nics'] should contain the pre-declared nics, then the networks
    that the server has a declared relationship to, then the networks
    of the ports the server has a relationship to.

    If that doesn't include the management network, it should be prepended
    as the first network.

    The management network id and name are stored in the server meta properties
    """
    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)
    management_network_id, management_network_name = \
        _get_management_network_id_and_name(neutron_client, ctx)

    if management_network_id or management_network_name:
        ctx.logger.warning(
            'A management_network_name was provided ({0}), '
            'however this node property is deprecated. '
            'Instead, use a '
            'cloudify.openstack.server_connected_to_port '
            'relationship to a '
            'cloudify.openstack.nodes.Port type '
            'or a cloudify.relationships.depends_on '
            'derived relationship to a '
            'cloudify.openstack.nodes.Network type '
            'node template. '
            'In Cloudify 3.4.x and above, relationships are ordered. '
            'NICS on a Server are ordered according to '
            'relationship order'.format(management_network_name))

    port_networks = get_port_networks(neutron_client, port_ids)

    for port_network in port_networks:
        for network_id in network_ids:
            if network_id in port_network.get('net-id'):
                network_ids.remove(network_id)

    nics = _merge_nics(
        management_network_id,
        server.get('nics', []),
        [{'net-id': net_id} for net_id in network_ids],
        port_networks)

    nics = _normalize_nics(nics)

    server['nics'] = nics
    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
Example #2
0
def _prepare_server_nics(neutron_client, ctx, server):
    """Update server['nics'] based on declared relationships.

    server['nics'] should contain the pre-declared nics, then the networks
    that the server has a declared relationship to, then the networks
    of the ports the server has a relationship to.

    If that doesn't include the management network, it should be prepended
    as the first network.

    The management network id and name are stored in the server meta properties
    """
    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)
    management_network_id, management_network_name = \
        _get_management_network_id_and_name(neutron_client, ctx)

    if management_network_id or management_network_name:
        ctx.logger.warning(
            'A management_network_name was provided ({0}), '
            'however this node property is deprecated. '
            'Instead, use a '
            'cloudify.openstack.server_connected_to_port '
            'relationship to a '
            'cloudify.openstack.nodes.Port type '
            'or a cloudify.relationships.depends_on '
            'derived relationship to a '
            'cloudify.openstack.nodes.Network type '
            'node template. '
            'In Cloudify 3.4.x and above, relationships are ordered. '
            'NICS on a Server are ordered according to '
            'relationship order'.format(management_network_name))

    port_networks = get_port_networks(neutron_client, port_ids)

    for port_network in port_networks:
        for network_id in network_ids:
            if network_id in port_network.get('net-id'):
                network_ids.remove(network_id)

    nics = _merge_nics(
        management_network_id,
        server.get('nics', []),
        [{'net-id': net_id} for net_id in network_ids],
        port_networks)

    nics = _normalize_nics(nics)

    server['nics'] = nics
    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
def _prepare_server_nics(neutron_client, ctx, server):
    """Update server['nics'] based on declared relationships.

    server['nics'] should contain the pre-declared nics, then the networks
    that the server has a declared relationship to, then the networks
    of the ports the server has a relationship to.

    If that doesn't include the management network, it should be prepended
    as the first network.

    The management network id and name are stored in the server meta properties
    """
    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)
    management_network_id, management_network_name = \
        _get_management_network_id_and_name(neutron_client, ctx)
    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")

    nics = _merge_nics(
        management_network_id,
        server.get('nics', []),
        [{'net-id': net_id} for net_id in network_ids],
        get_port_networks(neutron_client, port_ids))

    nics = _normalize_nics(nics)

    server['nics'] = nics
    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
Example #4
0
def _prepare_server_nics(neutron_client, ctx, server):
    """Update server['nics'] based on declared relationships.

    server['nics'] should contain the pre-declared nics, then the networks
    that the server has a declared relationship to, then the networks
    of the ports the server has a relationship to.

    If that doesn't include the management network, it should be prepended
    as the first network.

    The management network id and name are stored in the server meta properties
    """
    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)
    management_network_id, management_network_name = \
        _get_management_network_id_and_name(neutron_client, ctx)
    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")

    nics = _merge_nics(
        management_network_id,
        server.get('nics', []),
        [{'net-id': net_id} for net_id in network_ids],
        get_port_networks(neutron_client, port_ids))

    nics = _normalize_nics(nics)

    server['nics'] = nics
    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
    def test_get_ids_of_nodes_by_type(self):

        rel_spec = {
            "instance": {
                "runtime_properties": {
                    OPENSTACK_TYPE_PROPERTY: NETWORK_OPENSTACK_TYPE,
                    OPENSTACK_ID_PROPERTY: "the node id",
                }
            }
        }
        ctx = self._make_vm_ctx_with_relationships([rel_spec])
        ids = get_openstack_ids_of_connected_nodes_by_openstack_type(ctx, NETWORK_OPENSTACK_TYPE)
        self.assertEqual(["the node id"], ids)
    def test_get_ids_of_nodes_by_type(self):

        rel_spec = {
            'instance': {
                'runtime_properties': {
                    OPENSTACK_TYPE_PROPERTY: NETWORK_OPENSTACK_TYPE,
                    OPENSTACK_ID_PROPERTY: 'the node id'
                }
            }
        }
        ctx = self._make_vm_ctx_with_relationships([rel_spec])
        ids = get_openstack_ids_of_connected_nodes_by_openstack_type(
            ctx, NETWORK_OPENSTACK_TYPE)
        self.assertEqual(['the node id'], ids)
def _get_connected_ext_net_id(neutron_client):
    ext_net_ids = \
        [net_id
            for net_id in
            get_openstack_ids_of_connected_nodes_by_openstack_type(
                ctx, NETWORK_OPENSTACK_TYPE) if
            _check_if_network_is_external(neutron_client, net_id)]

    if len(ext_net_ids) > 1:
        raise NonRecoverableError(
            'More than one external network is connected to router {0}'
            ' by a relationship; External network IDs: {0}'.format(
                ext_net_ids))

    return ext_net_ids[0] if ext_net_ids else None
def _get_connected_ext_net_id(neutron_client):
    ext_net_ids = \
        [net_id
            for net_id in
            get_openstack_ids_of_connected_nodes_by_openstack_type(
                ctx, NETWORK_OPENSTACK_TYPE) if
            _check_if_network_is_external(neutron_client, net_id)]

    if len(ext_net_ids) > 1:
        raise NonRecoverableError(
            'More than one external network is connected to router {0}'
            ' by a relationship; External network IDs: {0}'.format(
                ext_net_ids))

    return ext_net_ids[0] if ext_net_ids else None
Example #9
0
def handle_image_from_relationship(obj_dict, property_name_to_put, ctx):
    images = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, IMAGE_OPENSTACK_TYPE)
    if images:
        obj_dict.update({property_name_to_put: images[0]})
Example #10
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, 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 _handle_security_groups(port):
    security_groups = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, SG_OPENSTACK_TYPE)
    if security_groups:
        port['security_groups'] = security_groups
def _handle_fixed_ips(port, neutron_client):
    """Combine IPs and Subnets for the Port fixed IPs list.

    The Port object looks something this:
    {
      'port': {
        'id': 'some-id',
        'fixed_ips': [
          {'subnet_id': 'subnet1', 'ip_address': '1.2.3.4'},
          {'ip_address': '1.2.3.5'},
          {'subnet_id': 'subnet3'},
        ]
      ...snip...
    }

    We need to combine subnets and ips from three sources:
    1) Fixed IPs and Subnets from the Port object.
    2) Subnets from relationships to subnets.
    3) A Fixed IP from node properties.

    There are some issues:
    1) Users can provide both subnets and relationships to subnets.
    2) Recurrences of the subnet_id indicate a desire
       for multiple IPs on that subnet.
    3) If we provide a fixed_ip, we don't also know the
       target subnet because of how the node properties are.
       We should change that.
       Have not yet changed that.
       But will need to support both paths anyway.

    :param port: An Openstack API Port Object.
    :param neutron_client: Openstack Neutron Client.
    :return: None
    """

    fixed_ips = port.get('fixed_ips', [])
    subnet_ids_from_port = [net.get('subnet_id') for net in fixed_ips]
    subnet_ids_from_rels = \
        get_openstack_ids_of_connected_nodes_by_openstack_type(
            ctx, SUBNET_OPENSTACK_TYPE)

    # Add the subnets from relationships to the port subnets.
    for subnet_from_rel in subnet_ids_from_rels:
        if subnet_from_rel not in subnet_ids_from_port:
            fixed_ips.append({'subnet_id': subnet_from_rel})

    addresses = [ip.get('ip_address') for ip in fixed_ips]
    fixed_ip_from_props = ctx.node.properties['fixed_ip']

    # If we have a fixed_ip from node props, we need to add it,
    # but first try to match it with one of our subnets.
    # The fixed_ip_element should be one of:
    # 1) {'ip_address': 'x.x.x.x'}
    # 2) {'subnet_id': '....'}
    # 3) {'ip_address': 'x.x.x.x', 'subnet_id': '....'}
    # show_subnet returns something like this:
    # subnet = {
    #   'subnet': {
    #     'id': 'subnet1',
    #     'cidr': '1.2.3.4/24',
    #     'allocation_pools': [],
    #     ...snip...
    #   }
    # }
    if fixed_ip_from_props and not (fixed_ip_from_props in addresses):
        fixed_ip_element = {'ip_address': fixed_ip_from_props}
        for fixed_ip in fixed_ips:
            subnet_id = fixed_ip.get('subnet_id')
            if not _valid_subnet_ip(fixed_ip_from_props,
                                    neutron_client.show_subnet(subnet_id)):
                continue
            fixed_ip_element['subnet_id'] = subnet_id
            del fixed_ips[fixed_ips.index(fixed_ip)]
            break
        fixed_ips.append(fixed_ip_element)

    # Finally update the object.
    if fixed_ips:
        port['fixed_ips'] = fixed_ips
Example #15
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']
def handle_image_from_relationship(obj_dict, property_name_to_put, ctx):
    images = get_openstack_ids_of_connected_nodes_by_openstack_type(
        ctx, IMAGE_OPENSTACK_TYPE)
    if images:
        obj_dict.update({property_name_to_put: images[0]})
Example #17
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']