def detach(nova_client, neutron_client, **kwargs):

    if is_external_relationship(ctx):
        ctx.logger.info('Not detaching port from server since '
                        'external port and server are being used')
        return

    port_id = get_openstack_id(ctx.target)
    server_id = get_openstack_id(ctx.source)

    server_floating_ip = get_server_floating_ip(neutron_client, server_id)
    if server_floating_ip:
        ctx.logger.info('We have floating ip {0} attached to server'.format(
            server_floating_ip['floating_ip_address']))
        server = nova_client.servers.get(server_id)
        server.remove_floating_ip(server_floating_ip['floating_ip_address'])
        return ctx.operation.retry(
            message='Waiting for the floating ip {0} to '
            'detach from server {1}..'.format(
                server_floating_ip['floating_ip_address'], server_id),
            retry_after=10)
    change = {PORT_OPENSTACK_TYPE: {'device_id': '', 'device_owner': ''}}
    ctx.logger.info('Detaching port {0}...'.format(port_id))
    neutron_client.update_port(port_id, change)
    ctx.logger.info('Successfully detached port {0}'.format(port_id))
def disconnect_security_group(nova_client, **kwargs):
    if is_external_relationship(ctx):
        ctx.logger.info('Not disconnecting security group and server since '
                        'external security group and server are being used')
        return

    server_id = get_openstack_id(ctx.source)
    security_group_id = get_openstack_id(ctx.target)
    security_group_name = ctx.target.instance.runtime_properties[
        OPENSTACK_NAME_PROPERTY]
    server = nova_client.servers.get(server_id)
    # to support nova security groups as well, we disconnect the security group
    # by name (as disconnecting by id doesn't seem to work well for nova SGs)
    try:
        server.remove_security_group(security_group_name)
    except nova_exceptions.NotFound:
        ctx.logger.warn("Security group '{0}' (id: {1}) is not attached "
                        "to server instance {2}; skipping".format(
                            security_group_name, security_group_id, server_id))
    else:
        _validate_security_group_and_server_connection_status(
            nova_client,
            server_id,
            security_group_id,
            security_group_name,
            is_connected=False)
Exemple #3
0
def connect_security_group(neutron_client, **kwargs):
    port_id = get_openstack_id(ctx.source)
    security_group_id = get_openstack_id(ctx.target)

    if is_external_relationship_not_conditionally_created(ctx):
        ctx.logger.info('Validating external port and security-group are '
                        'connected')
        if any(sg for sg in neutron_client.show_port(port_id)['port'].get(
                'security_groups', []) if sg == security_group_id):
            return
        raise NonRecoverableError(
            'Expected external resources port {0} and security-group {1} to '
            'be connected'.format(port_id, security_group_id))

    # WARNING: non-atomic operation
    port = neutron_client.cosmo_get(PORT_OPENSTACK_TYPE, id=port_id)
    ctx.logger.info(
        "connect_security_group(): source_id={0} target={1}".format(
            port_id, ctx.target.instance.runtime_properties))
    sgs = port['security_groups'] + [security_group_id]
    neutron_client.update_port(port_id,
                               {PORT_OPENSTACK_TYPE: {'security_groups': sgs}})

    # Double check if SG has been actually updated (a race-condition
    # in OpenStack):
    port_info = neutron_client.show_port(port_id)['port']
    port_security_groups = port_info.get('security_groups', [])
    if security_group_id not in port_security_groups:
        return ctx.operation.retry(
            message='Security group connection (`{0}\' -> `{1}\')'
                    ' has not been established!'.format(port_id,
                                                        security_group_id),
            retry_after=NO_SG_PORT_CONNECTION_RETRY_INTERVAL
        )
Exemple #4
0
def connect_floatingip(nova_client, fixed_ip, **kwargs):
    server_id = get_openstack_id(ctx.source)
    floating_ip_id = get_openstack_id(ctx.target)

    if is_external_relationship_not_conditionally_created(ctx):
        ctx.logger.info('Validating external floatingip and server '
                        'are associated')
        if nova_client.floating_ips.get(floating_ip_id).instance_id ==\
                server_id:
            return
        raise NonRecoverableError(
            'Expected external resources server {0} and floating-ip {1} to be '
            'connected'.format(server_id, floating_ip_id))

    floating_ip_address = ctx.target.instance.runtime_properties[
        IP_ADDRESS_PROPERTY]
    server = nova_client.servers.get(server_id)
    server.add_floating_ip(floating_ip_address, fixed_ip or None)

    server = nova_client.servers.get(server_id)
    all_server_ips = reduce(operator.add, server.networks.values())
    if floating_ip_address not in all_server_ips:
        return ctx.operation.retry(message='Failed to assign floating ip {0}'
                                           ' to machine {1}.'
                                   .format(floating_ip_address, server_id))
Exemple #5
0
def connect_security_group(nova_client, **kwargs):
    server_id = get_openstack_id(ctx.source)
    security_group_id = get_openstack_id(ctx.target)
    security_group_name = ctx.target.instance.runtime_properties[
        OPENSTACK_NAME_PROPERTY]

    if is_external_relationship_not_conditionally_created(ctx):
        ctx.logger.info('Validating external security group and server '
                        'are associated')
        server = nova_client.servers.get(server_id)
        if [sg for sg in server.list_security_group() if sg.id ==
                security_group_id]:
            return
        raise NonRecoverableError(
            'Expected external resources server {0} and security-group {1} to '
            'be connected'.format(server_id, security_group_id))

    server = nova_client.servers.get(server_id)
    for security_group in server.list_security_group():
        # Since some security groups are already attached in
        # create this will ensure that they are not attached twice.
        if security_group_id != security_group.id and \
                security_group_name != security_group.name:
            # to support nova security groups as well,
            # we connect the security group by name
            # (as connecting by id
            # doesn't seem to work well for nova SGs)
            server.add_security_group(security_group_name)

    _validate_security_group_and_server_connection_status(nova_client,
                                                          server_id,
                                                          security_group_id,
                                                          security_group_name,
                                                          is_connected=True)
Exemple #6
0
def attach_volume(nova_client, cinder_client, status_attempts,
                  status_timeout, **kwargs):
    server_id = get_openstack_id(ctx.target)
    volume_id = get_openstack_id(ctx.source)

    if is_external_relationship_not_conditionally_created(ctx):
        ctx.logger.info('Validating external volume and server '
                        'are connected')
        attachment = volume.get_attachment(cinder_client=cinder_client,
                                           volume_id=volume_id,
                                           server_id=server_id)
        if attachment:
            return
        else:
            raise NonRecoverableError(
                'Expected external resources server {0} and volume {1} to be '
                'connected'.format(server_id, volume_id))

    # Note: The 'device_name' property should actually be a property of the
    # relationship between a server and a volume; It'll move to that
    # relationship type once relationship properties are better supported.
    device = ctx.source.node.properties[volume.DEVICE_NAME_PROPERTY]
    nova_client.volumes.create_server_volume(
        server_id,
        volume_id,
        device if device != 'auto' else None)
    try:
        vol, wait_succeeded = volume.wait_until_status(
            cinder_client=cinder_client,
            volume_id=volume_id,
            status=volume.VOLUME_STATUS_IN_USE,
            num_tries=status_attempts,
            timeout=status_timeout
        )
        if not wait_succeeded:
            raise RecoverableError(
                'Waiting for volume status {0} failed - detaching volume and '
                'retrying..'.format(volume.VOLUME_STATUS_IN_USE))
        if device == 'auto':
            # The device name was assigned automatically so we
            # query the actual device name
            attachment = volume.get_attachment(
                cinder_client=cinder_client,
                volume_id=volume_id,
                server_id=server_id
            )
            device_name = attachment['device']
            ctx.logger.info('Detected device name for attachment of volume '
                            '{0} to server {1}: {2}'
                            .format(volume_id, server_id, device_name))
            ctx.source.instance.runtime_properties[
                volume.DEVICE_NAME_PROPERTY] = device_name
    except Exception, e:
        if not isinstance(e, NonRecoverableError):
            _prepare_attach_volume_to_be_repeated(
                nova_client, cinder_client, server_id, volume_id,
                status_attempts, status_timeout)
        raise
Exemple #7
0
def connect_port(neutron_client, **kwargs):
    if is_external_relationship_not_conditionally_created(ctx):
        return

    port_id = get_openstack_id(ctx.source)
    floating_ip_id = get_openstack_id(ctx.target)
    fip = {'port_id': port_id}
    neutron_client.update_floatingip(floating_ip_id,
                                     {FLOATINGIP_OPENSTACK_TYPE: fip})
Exemple #8
0
def update(nova_client, args, **kwargs):
    if HOST_AGGREGATE_OPENSTACK_TYPE in args:
        host_aggregate = nova_client.aggregates.update(
            get_openstack_id(ctx), args.get(HOST_AGGREGATE_OPENSTACK_TYPE))

        set_openstack_runtime_properties(ctx, host_aggregate,
                                         HOST_AGGREGATE_OPENSTACK_TYPE)

    _set_metadata(ctx, nova_client, get_openstack_id(ctx), args)
Exemple #9
0
def delete(nova_client, **kwargs):
    if not is_external_resource(ctx):
        host_aggregate = nova_client.aggregates.get(get_openstack_id(ctx))
        _remove_hosts(ctx, nova_client, get_openstack_id(ctx),
                      host_aggregate.hosts)

        if HOSTS_PROPERTY in ctx.instance.runtime_properties:
            ctx.instance.runtime_properties.pop(HOSTS_PROPERTY, None)

    delete_resource_and_runtime_properties(ctx, nova_client,
                                           RUNTIME_PROPERTIES_KEYS)
Exemple #10
0
def detach_volume(nova_client, cinder_client, status_attempts,
                  status_timeout, **kwargs):
    if is_external_relationship(ctx):
        ctx.logger.info('Not detaching volume from server since '
                        'external volume and server are being used')
        return

    server_id = get_openstack_id(ctx.target)
    volume_id = get_openstack_id(ctx.source)

    _detach_volume(nova_client, cinder_client, server_id, volume_id,
                   status_attempts, status_timeout)
def update(nova_client, args, **kwargs):
    host_aggregate_dict = create_object_dict(ctx,
                                             HOST_AGGREGATE_OPENSTACK_TYPE,
                                             args)

    _remove_hosts(ctx, nova_client, get_openstack_id(ctx), kwargs)
    host_aggregate = nova_client.aggregates.update(get_openstack_id(ctx),
                                                   host_aggregate_dict)
    _add_hosts(ctx, nova_client, host_aggregate, kwargs)
    _set_metadata(ctx, nova_client, host_aggregate, kwargs)

    set_openstack_runtime_properties(ctx, host_aggregate,
                                     HOST_AGGREGATE_OPENSTACK_TYPE)
def disconnect_subnet(neutron_client, update_args=None, **kwargs):

    if update_args is not None and isinstance(update_args, dict):
        update_router(neutron_client, args=update_args, ctx=ctx)

    if is_external_relationship(ctx):
        ctx.logger.info('Not connecting subnet and router since external '
                        'subnet and router are being used')
        return

    neutron_client.remove_interface_router(
        get_openstack_id(ctx.target),
        {'subnet_id': get_openstack_id(ctx.source)})
def attach(nova_client, neutron_client, **kwargs):

    if is_external_relationship(ctx):
        ctx.logger.info('Not attaching port from server since '
                        'external port and server are being used')
        return

    server_id = get_openstack_id(ctx.source)
    port_id = get_openstack_id(ctx.target)
    port = neutron_client.show_port(port_id)
    server = nova_client.servers.get(server_id)
    network = neutron_client.show_network(port['port']['network_id'])
    network_name = network['network']['name']

    floating_ip_address = None
    for target in ctx.target.instance.relationships:
        if target.type == PORT_ADDRESS_REL_TYPE:
            target_instance = target.target.instance
            floatingip_id = \
                target_instance.runtime_properties[OPENSTACK_ID_PROPERTY]
            floating_ip = neutron_client.show_floatingip(floatingip_id)
            floating_ip_address = \
                floating_ip['floatingip']['floating_ip_address']

    server_addresses = \
        [addr['addr'] for addr in server.addresses[network_name]]

    if floating_ip_address and floating_ip_address not in server_addresses:
        ctx.logger.info('We will attach floating ip {0} to server {1}'.format(
            floating_ip_address, server_id))
        server.add_floating_ip(floating_ip_address)
        return ctx.operation.retry(
            message='Waiting for the floating ip {0} to '
            'attach to server {1}..'.format(floating_ip_address, server_id),
            retry_after=10)
    change = {
        PORT_OPENSTACK_TYPE: {
            'device_id': server_id,
        }
    }
    device_id = port['port'].get('device_id')
    if not device_id or device_id != server_id:
        ctx.logger.info('Attaching port {0}...'.format(port_id))
        neutron_client.update_port(port_id, change)
        ctx.logger.info('Successfully attached port {0}'.format(port_id))
    else:
        ctx.logger.info('Skipping port {0} attachment, '
                        'because it is already attached '
                        'to device (server) id {1}.'.format(
                            port_id, device_id))
def disconnect_subnet(neutron_client, **kwargs):
    if is_external_relationship(ctx):
        ctx.logger.info('Not connecting subnet and router since external '
                        'subnet and router are being used')
        return
    node_routes = ctx.source.instance.runtime_properties.get(
        ROUTES_OPENSTACK_TYPE)

    # Only delete routes only if it has "routes" as runtime properties
    if node_routes:
        _delete_routes(neutron_client)

    neutron_client.remove_interface_router(
        get_openstack_id(ctx.target),
        {'subnet_id': get_openstack_id(ctx.source)})
def update_project(keystone_client, args, **kwargs):

    project_dict = create_object_dict(ctx, PROJECT_OPENSTACK_TYPE, args,
                                      {'domain': 'default'})
    project_dict[PROJECT_OPENSTACK_TYPE] = get_openstack_id(ctx)
    project = keystone_client.projects.update(**project_dict)
    set_openstack_runtime_properties(ctx, project, PROJECT_OPENSTACK_TYPE)
def create(neutron_client, args, **kwargs):

    if use_external_resource(ctx, neutron_client, SUBNET_OPENSTACK_TYPE):
        try:
            net_id = \
                get_openstack_id_of_single_connected_node_by_openstack_type(
                    ctx, NETWORK_OPENSTACK_TYPE, True)

            if net_id:
                subnet_id = get_openstack_id(ctx)

                if neutron_client.show_subnet(
                        subnet_id)[SUBNET_OPENSTACK_TYPE][NETWORK_ID] \
                        != net_id:
                    raise NonRecoverableError(
                        'Expected external resources subnet {0} and network'
                        ' {1} to be connected'.format(subnet_id, net_id))
            return
        except Exception:
            delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
            raise

    net_id = get_openstack_id_of_single_connected_node_by_openstack_type(
        ctx, NETWORK_OPENSTACK_TYPE)
    subnet = create_object_dict(ctx,
                                SUBNET_OPENSTACK_TYPE,
                                args,
                                {NETWORK_ID: net_id})

    s = neutron_client.create_subnet(
        {SUBNET_OPENSTACK_TYPE: subnet})[SUBNET_OPENSTACK_TYPE]
    set_neutron_runtime_properties(ctx, s, SUBNET_OPENSTACK_TYPE)
def snapshot_apply(cinder_client, **kwargs):
    volume_id = get_openstack_id(ctx)

    backup_name = _get_snapshot_name(ctx, kwargs)
    snapshot_incremental = kwargs["snapshot_incremental"]
    if not snapshot_incremental:
        ctx.logger.info("Backup apply {} to {}".format(backup_name, volume_id))
        search_opts = {
            'volume_id': volume_id,
            VOLUME_OPENSTACK_ID_KEY: backup_name
        }

        backups = cinder_client.backups.list(
            search_opts=search_opts)

        for backup in backups:
            # if returned more than one backup, use first
            if backup.name == backup_name:
                ctx.logger.debug("Used first with {} to {}"
                                 .format(backup.id, volume_id))
                cinder_client.restores.restore(backup.id, volume_id)
                break
        else:
            raise cfy_exc.NonRecoverableError("No such {} backup."
                                              .format(backup_name))
    else:
        ctx.logger.error("Apply snapshot is unsuported")
def connect_subnet(neutron_client, **kwargs):
    router_id = get_openstack_id(ctx.target)
    subnet_id = get_openstack_id(ctx.source)

    if is_external_relationship_not_conditionally_created(ctx):
        ctx.logger.info('Validating external subnet and router '
                        'are associated')
        for port in neutron_client.list_ports(device_id=router_id)['ports']:
            for fixed_ip in port.get('fixed_ips', []):
                if fixed_ip.get('subnet_id') == subnet_id:
                    return
        raise NonRecoverableError(
            'Expected external resources router {0} and subnet {1} to be '
            'connected'.format(router_id, subnet_id))

    neutron_client.add_interface_router(router_id, {'subnet_id': subnet_id})
def get_project_quota(nova_client, cinder_client, neutron_client, **kwargs):
    project_id = get_openstack_id(ctx)
    quota = ctx.instance.runtime_properties.get(QUOTA, {})
    quota[NOVA] = get_quota(project_id, nova_client, NOVA)
    quota[NEUTRON] = get_quota(project_id, neutron_client, NEUTRON)
    quota[CINDER] = get_quota(project_id, cinder_client, CINDER)
    ctx.instance.runtime_properties[QUOTA] = quota
def create(neutron_client, args, **kwargs):

    if use_external_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE):
        try:
            ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client)

            if ext_net_id_by_rel:
                router_id = get_openstack_id(ctx)

                router = neutron_client.show_router(router_id)['router']
                if not (router['external_gateway_info']
                        and 'network_id' in router['external_gateway_info']
                        and router['external_gateway_info']['network_id']
                        == ext_net_id_by_rel):
                    raise NonRecoverableError(
                        'Expected external resources router {0} and '
                        'external network {1} to be connected'.format(
                            router_id, ext_net_id_by_rel))
            return
        except Exception:
            delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
            raise

    router = create_object_dict(ctx, ROUTER_OPENSTACK_TYPE, args, {})
    ctx.logger.info('router: {0}'.format(router))

    _handle_external_network_config(router, neutron_client)

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

    set_neutron_runtime_properties(ctx, r, ROUTER_OPENSTACK_TYPE)
Exemple #21
0
def update_project_quota(nova_client,
                         cinder_client,
                         neutron_client,
                         quota,
                         **kwargs):
    project_id = get_openstack_id(ctx)
    update_quota(project_id, quota, nova_client, NOVA)
    update_quota(project_id, quota, neutron_client, NEUTRON)
    update_quota(project_id, quota, cinder_client, CINDER)
def _remove_protected(glance_client):
    if use_external_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE):
        return

    is_protected = ctx.node.properties[IMAGE_OPENSTACK_TYPE].get(
        'protected', False)
    if is_protected:
        img_id = get_openstack_id(ctx)
        glance_client.images.update(img_id, protected=False)
Exemple #23
0
def delete(keystone_client, nova_client, cinder_client,
           neutron_client, **kwargs):
    project_id = get_openstack_id(ctx)
    quota = ctx.node.properties[PROJECT_QUOTA_TYPE]
    delete_quota(project_id, quota, nova_client, NOVA)
    delete_quota(project_id, quota, neutron_client, NEUTRON)
    delete_quota(project_id, quota, cinder_client, CINDER)
    delete_resource_and_runtime_properties(ctx, keystone_client,
                                           RUNTIME_PROPERTIES_KEYS)
def update_router(neutron_client, args, **kwargs):

    from copy import deepcopy

    def dict_merge(a, b):
        if isinstance(a, list) and isinstance(b, list):
            a.append(b)
            return a
        if not isinstance(b, dict):
            return b
        result = deepcopy(a)
        for k, v in b.iteritems():
            if k in result and isinstance(result[k], dict):
                result[k] = dict_merge(result[k], v)
            else:
                result[k] = deepcopy(v)
        return result

    # Find out if the update script is being called
    # from a relationship or a node operation.
    if ctx.type == RELATIONSHIP_INSTANCE:
        if ROUTER_OPENSTACK_TYPE in get_openstack_type(ctx.source):
            subject = ctx.source
        elif ROUTER_OPENSTACK_TYPE in get_openstack_type(ctx.target):
            subject = ctx.target
        else:
            raise NonRecoverableError(
                'Neither target nor source is {0}'.format(
                    ROUTER_OPENSTACK_TYPE))
    else:
        subject = ctx

    try:
        router = neutron_client.show_router(get_openstack_id(subject))
    except NeutronClientException as e:
        raise NonRecoverableError('Error: {0}'.format(str(e)))
    if not isinstance(router, dict) or \
            'router' not in router.keys() or \
            'id' not in router['router'].keys():
        raise NonRecoverableError(
            'API returned unexpected structure.: {0}'.format(router))

    router_id = router['router'].pop('id')

    new_router = {'router': {}}
    for key, value in args.items():
        new_router['router'][key] = value

    for ro_attribute in ['status', 'tenant_id']:
        try:
            del router['router'][ro_attribute]
        except KeyError:
            pass

    dict_merge(new_router, router)
    ctx.logger.info(new_router)
    neutron_client.update_router(router_id, new_router)
def delete(cinder_client, **kwargs):
    # seach snapshots for volume
    search_opts = {
        'volume_id': get_openstack_id(ctx),
    }
    _delete_snapshot(cinder_client, search_opts)
    # remove volume itself
    delete_resource_and_runtime_properties(ctx, cinder_client,
                                           RUNTIME_PROPERTIES_KEYS)
Exemple #26
0
def disconnect_port(neutron_client, **kwargs):
    if is_external_relationship(ctx):
        ctx.logger.info('Not disassociating floatingip and port since '
                        'external floatingip and port are being used')
        return

    floating_ip_id = get_openstack_id(ctx.target)
    fip = {'port_id': None}
    neutron_client.update_floatingip(floating_ip_id,
                                     {FLOATINGIP_OPENSTACK_TYPE: fip})
def delete(nova_client, **kwargs):
    if not is_external_resource(ctx):
        ctx.logger.info('deleting server group')

        nova_client.server_groups.delete(get_openstack_id(ctx))
    else:
        ctx.logger.info('not deleting server group since an external server '
                        'group is being used')

    delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)
def stop(neutron_client, **kwargs):
    if is_external_resource(ctx):
        ctx.logger.info('Not stopping network since an external network is '
                        'being used')
        return

    neutron_client.update_network(
        get_openstack_id(ctx),
        {NETWORK_OPENSTACK_TYPE: {
            ADMIN_STATE_UP: False
        }})
Exemple #29
0
def assign_users(users, keystone_client, **kwargs):
    project_id = get_openstack_id(ctx)
    for user in users:
        roles = user[ROLES]
        u = keystone_client.users.find(name=user['name'])
        for role in roles:
            r = keystone_client.roles.find(name=role)
            keystone_client.roles.grant(user=u.id,
                                        project=project_id,
                                        role=r.id)
            ctx.logger.debug("Assigned user {0} to project {1} with role {2}"
                             .format(u.id, project_id, r.id))
def delete(nova_client, **kwargs):
    if not is_external_resource(ctx):
        ctx.logger.info('deleting keypair')

        _delete_private_key_file()

        nova_client.keypairs.delete(get_openstack_id(ctx))
    else:
        ctx.logger.info('not deleting keypair since an external keypair is '
                        'being used')

    delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS)