Пример #1
0
def generate_instance_info(instance_id, style=None):
    nc = nova.client()
    kc = keystone.client()
    gc = glance.get_glance_client(kc)

    try:
        instance = nc.servers.get(instance_id)
    except n_exc.NotFound:
        error("Instance {} not found".format(instance_id))

    info = instance._info.copy()
    for network_label, address_list in instance.networks.items():
        info["%s network" % network_label] = ", ".join(address_list)

    flavor = info.get("flavor", {})
    flavor_id = flavor.get("id", "")

    try:
        info["flavor"] = "%s (%s)" % (nova.get_flavor(nc, flavor_id).name, flavor_id)
    except Exception:
        info["flavor"] = "%s (%s)" % ("Flavor not found", flavor_id)

    # Image
    image = info.get("image", {})
    if image:
        image_id = image.get("id", "")
        try:
            img = gc.images.get(image_id)
            nectar_build = img.properties.get("nectar_build", "N/A")
            info["image"] = "%s (%s, NeCTAR Build %s)" % (img.name, img.id, nectar_build)
        except Exception:
            info["image"] = "Image not found (%s)" % image_id
    else:  # Booted from volume
        info["image"] = "Attempt to boot from volume - no image supplied"

    # Tenant
    tenant_id = info.get("tenant_id")
    if tenant_id:
        try:
            tenant = keystone.get_tenant(kc, tenant_id)
            info["tenant_id"] = "%s (%s)" % (tenant.name, tenant.id)
        except Exception:
            pass

    # User
    user_id = info.get("user_id")
    if user_id:
        try:
            user = keystone.get_user(kc, user_id)
            info["user_id"] = "%s (%s)" % (user.name, user.id)
        except Exception:
            pass

    # Remove stuff
    info.pop("links", None)
    info.pop("addresses", None)
    info.pop("hostId", None)
    info.pop("security_groups", None)

    return _format_instance(info, style=style)
Пример #2
0
def compare_quotas(name_or_id=None):
    """Compare the allocation and quota information for a tenant
    """
    if name_or_id == None:
        print 'A tenant name or id is required'
        return
        
    keystone_api = hm_keystone.client_session(version=3)
    try:
        tenant = hm_keystone.get_tenant(keystone_api, name_or_id)
    except:
        print 'Tenant {0} not found in keystone'.format(name_or_id)
        return
        
    nova_api = hm_nova.client()
    quotas = nova_api.quotas.get(tenant.id)
    print 'nova quotas: instances {0}, cores {1}, ram {2}'.format(
        quotas.instances, quotas.cores, quotas.ram / 1024)
    usage = _get_usage(nova_api, _get_flavor_map(nova_api), tenant.id)
    print 'nova usage: instances {0}, cores {1}, ram {2}'.format(
        usage['instances'], usage['vcpus'], usage['ram'] / 1024)

    allocations_api = NectarApiSession()
    allocations = allocations_api.get_allocations(); 
    tenant_allocations = filter(lambda x: x['tenant_uuid'] == tenant.id and \
                                (x['status'] == 'A' or x['status'] == 'X'),
                                allocations)
    if len(tenant_allocations) == 0:
        print 'No approved allocation records for tenant {0} / {1}'.format(
            tenant.id, tenant.name)
        return

    tenant_allocations.sort(key=lambda alloc: alloc['modified_time'])
    current_allocation = tenant_allocations[-1]
    
    format = '{0} mismatch: allocated {1}, nova {2}, used {3}'
    if current_allocation['instance_quota'] != quotas.instances:
        print format.format('Instance quota',
                            current_allocation['instance_quota'], 
                            quotas.instances,
                            usage['instances'])
    if current_allocation['core_quota'] != quotas.cores:
        print format.format('VCPU quota',
                            current_allocation['core_quota'], 
                            quotas.cores,
                            usage['vcpus'])
    if current_allocation['ram_quota'] * 1024 != quotas.ram:
        print format.format('RAM quota',
                            current_allocation['ram_quota'] * 1024, 
                            quotas.ram,
                            usage['ram'])
Пример #3
0
def get_ticket_recipients(instance):
    """Build a list of email addresses"""
    email_addresses = []

    kc = keystone.client()
    user = keystone.get_user(kc, instance.user_id)
    if user.email:
        email_addresses.append(user.email)

    # Add tenant members to ticket recipient list
    tenant = keystone.get_tenant(kc, instance.tenant_id)
    for user in tenant.list_users():
        roles = [r.name for r in user.list_roles(tenant)]
        if 'TenantManager' in roles:
            email_addresses.append(user.email)
    return email_addresses
Пример #4
0
def purge_project(tenant_name, dry_run=True):
    """Purge resources and disable a given project """
    if not spawn.find_executable('ospurge'):
        error('ospurge not found in path. Please ensure it is installed.')
    username, password = get_creds()

    if dry_run:
        print("Running in dry-run mode")

    ks_client = keystone.client()
    tenant = keystone.get_tenant(ks_client, tenant_name)
    tenant_member_role = ks_client.roles.find(name='Member')
    ospurge_user = keystone.get_user(ks_client, username)

    if not tenant.enabled:
        print("Enabling project for purge")
        tenant.update(enabled=True)

    if not is_in_project(tenant, ospurge_user):
        print("Adding ospurge user to project")
        tenant.add_user(ospurge_user, tenant_member_role)

    if dry_run:
        run_opt = '--dry-run'
    else:
        run_opt = '--verbose'

    cmd = ("ospurge --dont-delete-project --own-project --username {username} "
           "--password {password} --admin-project {tenant} {run_opt}"
           "".format(username=username, password=password,
                     tenant=tenant.name, run_opt=run_opt))
    print("Running: {}".format(cmd.replace(password, 'xxxx')))
    run(cmd)

    if is_in_project(tenant, ospurge_user):
        print("Removing ospurge user from project")
        tenant.remove_user(ospurge_user, tenant_member_role)

    if tenant.enabled:
        if dry_run and tenant.enabled:
            print("Not disabling project due to dry-run")
        else:
            print("Disabling project")
            tenant.update(enabled=False)
            keystone.set_project_metadata(tenant_name,
                                          'ospurge_date',
                                          str(datetime.datetime.now()))
Пример #5
0
def get_images_tenant(tenant_id_or_name, tenant_type):
    """fetch tenant id from config file"""
    if tenant_id_or_name is None:
        msg = " ".join(("No tenant set.", "Please set tenant in",
                        "[cfg:hivemind_contrib.glance.%s]" % tenant_type))
        error(msg)
    try:
        ks_client = keystone.client()
        tenant = keystone.get_tenant(ks_client, tenant_id_or_name)
    except ks_exc.NotFound:
        raise error("Tenant {} not found. Check your settings."
                    .format(tenant_id_or_name))
    except ks_exc.Forbidden:
        raise error("Permission denied. Check you're using admin credentials.")
    except Exception as e:
        raise error(e)

    return tenant
Пример #6
0
def lock_instance(instance_id, dry_run=True):
    """pause and lock an instance"""
    if dry_run:
        print('Running in dry-run mode (use --no-dry-run for realsies)')

    fd = get_freshdesk_client()
    nc = nova.client()
    kc = keystone.client()
    try:
        instance = nc.servers.get(instance_id)
    except n_exc.NotFound:
        error('Instance {} not found'.format(instance_id))

    ticket_id = None
    ticket_url = instance.metadata.get('security_ticket')
    if ticket_url:
        print('Found existing ticket: {}'.format(ticket_url))
        ticket_id = int(ticket_url.split('/')[-1])

        if dry_run:
            print('Would set ticket #{} status to open/urgent'
                  .format(ticket_id))
        else:
            # Set ticket status=waiting for customer, priority=urgent
            print('Setting ticket #{} status to open/urgent'.format(ticket_id))
            fd.tickets.update_ticket(ticket_id, status=6, priority=4)
    else:
        tenant = keystone.get_tenant(kc, instance.tenant_id)
        user = keystone.get_user(kc, instance.user_id)
        email_addresses = get_ticket_recipients(instance)

        # Create ticket if none exist, and add instance info
        subject = 'Security incident for instance {}'.format(instance_id)
        body = '<br />\n'.join([
            'Dear NeCTAR Research Cloud User, ',
            '',
            '',
            'We have reason to believe that cloud instance: '
            '<b>{} ({})</b>'.format(instance.name, instance.id),
            'in the project <b>{}</b>'.format(tenant.name),
            'created by <b>{}</b>'.format(user.email),
            'has been involved in a security incident.',
            '',
            'We have opened this helpdesk ticket to track the details and ',
            'the progress of the resolution of this issue.',
            '',
            'Please reply to this email if you have any questions or ',
            'concerns.',
            '',
            'Thanks, ',
            'NeCTAR Research Cloud Team'
        ])

        if dry_run:
            print('Would create ticket with details:')
            print('  To:      {}'.format(email_addresses))
            print('  Subject: {}'.format(subject))

            print('Would add instance details to ticket:')
            print(generate_instance_info(instance_id))
            print(generate_instance_sg_rules_info(instance_id))
        else:
            print('Creating new Freshdesk ticket')
            ticket = fd.tickets.create_ticket(
                description=body,
                subject=subject,
                email='*****@*****.**',
                cc_emails=email_addresses,
                priority=4,
                status=6,
                tags=['security'])
            ticket_id = ticket.id
            ticket_url = 'https://{}/helpdesk/tickets/{}'\
                         .format(fd.domain, ticket_id)
            nc.servers.set_meta(instance_id, {'security_ticket': ticket_url})
            print('Ticket #{} has been created: {}'
                  .format(ticket_id, ticket_url))

            # Add a private note with instance details
            print('Adding instance information to ticket')
            instance_info = generate_instance_info(instance_id, style='html')
            sg_info = generate_instance_sg_rules_info(instance_id,
                                                      style='html')
            body = '<br/><br/>'.join([instance_info, sg_info])
            fd.comments.create_note(ticket_id, body)

    if dry_run:
        if instance.status != 'ACTIVE':
            print('Instance state {}, will not pause'.format(instance.status))
        else:
            print('Would pause and lock instance {}'.format(instance_id))

        print('Would update ticket with action')
    else:
        # Pause and lock
        if instance.status != 'ACTIVE':
            print('Instance not in ACTIVE state ({}), skipping'
                  .format(instance.status))
        else:
            print('Pausing instance {}'.format(instance_id))
            instance.pause()

        print('Locking instance {}'.format(instance_id))
        instance.lock()

        # Add reply to user
        email_addresses = get_ticket_recipients(instance)
        print('Replying to ticket with action details')
        action = 'Instance <b>{} ({})</b> has been <b>paused and locked</b> '\
                 'pending further investigation'\
                 .format(instance.name, instance_id)
        fd.comments.create_reply(ticket_id, action, cc_emails=email_addresses)