Beispiel #1
0
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=100, logger=None):
        """
        Format hosts as "amqp://*****:*****@host:port"
        max_retries=0 defaults to unlimited retries

        """

        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
        self.unsend = OrderedDict()
        self.consume_promises = []
        self.exchanges = []
        if logger:
            self.log = logger
        else:
            logger = logging.getLogger("amqp")
            logging.basicConfig()
            self.log = logger
Beispiel #2
0
def pprint_volume(volume, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of volume %s in DB" % volume.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = volume.userid

    volume_type = volume.volume_type
    volume_dict = OrderedDict([
        ("id", volume.id),
        ("size", volume.size),
        ("disk_template", volume_type.template),
        ("disk_provider", volume_type.provider),
        ("server_id", volume.machine_id),
        ("userid", volume.userid),
        ("project", volume.project),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("index", volume.index),
        ("name", volume.name),
        ("state", volume.status),
        ("delete_on_termination", volume.delete_on_termination),
        ("deleted", volume.deleted),
        ("backendjobid", volume.backendjobid),
    ])

    pprint_table(stdout,
                 volume_dict.items(),
                 None,
                 separator=" | ",
                 title=title)
Beispiel #3
0
def pprint_network(network, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Network %s in DB" % network.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = network.userid

    db_network = OrderedDict([
        ("name", network.name),
        ("backend-name", network.backend_id),
        ("state", network.state),
        ("userid", userid),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("public", network.public),
        ("floating_ip_pool", network.floating_ip_pool),
        ("external_router", network.external_router),
        ("drained", network.drained),
        ("MAC prefix", network.mac_prefix),
        ("flavor", network.flavor),
        ("link", network.link),
        ("mode", network.mode),
        ("deleted", network.deleted),
        ("tags", "), ".join(network.backend_tag)),
        ("action", network.action)])

    pprint_table(stdout, db_network.items(), None, separator=" | ",
                 title=title)
Beispiel #4
0
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=100, logger=None):
        """
        Format hosts as "amqp://*****:*****@host:port"
        max_retries=0 defaults to unlimited retries

        """

        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
        self.unsend = OrderedDict()
        self.consume_promises = []
        self.exchanges = []
        if logger:
            self.log = logger
        else:
            logger = logging.getLogger("amqp")
            logging.basicConfig()
            self.log = logger
Beispiel #5
0
def pprint_volume(volume, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of volume %s in DB" % volume.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = volume.userid

    volume_type = volume.volume_type
    volume_dict = OrderedDict([
        ("id", volume.id),
        ("size", volume.size),
        ("disk_template", volume_type.template),
        ("disk_provider", volume_type.provider),
        ("server_id", volume.machine_id),
        ("userid", volume.userid),
        ("project", volume.project),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("index", volume.index),
        ("name", volume.name),
        ("state", volume.status),
        ("delete_on_termination", volume.delete_on_termination),
        ("deleted", volume.deleted),
        ("backendjobid", volume.backendjobid),
        ])

    pprint_table(stdout, volume_dict.items(), None, separator=" | ",
                 title=title)
Beispiel #6
0
def pprint_ippool(subnet, stdout=None, title=None):
    """Pretty print IP Pools of a subnet. Only IPv4 subnets have IP Pools"""

    if int(subnet.ipversion) != 4:
        return 0

    if stdout is None:
        stdout = sys.stdout

    stdout.write("IP Pools of subnet %s:\n\n" % subnet.id)

    for pool in subnet.get_ip_pools():
        size = pool.pool_size
        available = pool.available.count()
        info = OrderedDict([("First_IP", pool.return_start()),
                            ("Last_IP", pool.return_end()),
                            ("Size", size),
                            ("Available", available)])
        pprint_table(stdout, info.items(), None, separator=" | ", title=None)

        reserved = [pool.index_to_value(index)
                    for index, ip in enumerate(pool.reserved[:size])
                    if ip is False]

        if reserved != []:
            stdout.write("\nExternally Reserved IPs:\n\n")
            stdout.write(", ".join(reserved) + "\n")

        ip_sum = pool.available[:size] & pool.reserved[:size]
        pprint_pool(None, bitarray_to_map(ip_sum), 80, stdout)
        stdout.write("\n\n")
Beispiel #7
0
def project_fields(project):
    app = project.last_application
    pending_app = (app.id if app and app.state == app.PENDING else None)

    d = OrderedDict([
        ('project id', project.uuid),
        ('name', project.realname),
        ('status', project.state_display()),
        ('pending_app', pending_app),
        ('owner', project.owner),
        ('homepage', project.homepage),
        ('description', project.description),
        ('creation date', project.creation_date),
        ('request end date', project.end_date),
    ])

    deact = project.last_deactivation()
    if deact is not None:
        d['deactivation date'] = deact.date

    d.update([
        ('join policy', project.member_join_policy_display),
        ('leave policy', project.member_leave_policy_display),
        ('max members', units.show(project.limit_on_members_number, None)),
        ('total members', project.members_count()),
    ])

    return d
Beispiel #8
0
def pprint_network(network, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Network %s in DB" % network.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = network.userid

    db_network = OrderedDict([
        ("name", network.name), ("backend-name", network.backend_id),
        ("state", network.state), ("userid", userid),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("public", network.public),
        ("floating_ip_pool", network.floating_ip_pool),
        ("external_router", network.external_router),
        ("drained", network.drained), ("MAC prefix", network.mac_prefix),
        ("flavor", network.flavor), ("link", network.link),
        ("mode", network.mode), ("deleted", network.deleted),
        ("tags", "), ".join(network.backend_tag)), ("action", network.action)
    ])

    pprint_table(stdout,
                 db_network.items(),
                 None,
                 separator=" | ",
                 title=title)
Beispiel #9
0
def pprint_ippool(subnet, stdout=None, title=None):
    """Pretty print IP Pools of a subnet. Only IPv4 subnets have IP Pools"""

    if int(subnet.ipversion) != 4:
        return 0

    if stdout is None:
        stdout = sys.stdout

    stdout.write("IP Pools of subnet %s:\n\n" % subnet.id)

    for pool in subnet.get_ip_pools():
        size = pool.pool_size
        available = pool.available.count()
        info = OrderedDict([("First_IP", pool.return_start()),
                            ("Last_IP", pool.return_end()), ("Size", size),
                            ("Available", available)])
        pprint_table(stdout, info.items(), None, separator=" | ", title=None)

        reserved = [
            pool.index_to_value(index)
            for index, ip in enumerate(pool.reserved[:size]) if ip is False
        ]

        if reserved != []:
            stdout.write("\nExternally Reserved IPs:\n\n")
            stdout.write(", ".join(reserved) + "\n")

        ip_sum = pool.available[:size] & pool.reserved[:size]
        pprint_pool(None, bitarray_to_map(ip_sum), 80, stdout)
        stdout.write("\n\n")
Beispiel #10
0
def pprint_floating_ip(ip, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Floating IP %s" % ip.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = ip.userid

    vtype_info = OrderedDict([
        ("id", ip.id),
        ("address", ip.address),
        ("network", ip.network_id),
        ("port", ip.nic_id),
        ("server", ip.nic.machine_id),
        ("userid", userid),
        ("username", ucache.get_name(userid) if
         (display_mails and userid is not None) else None),
        ("project", ip.project),
        ("shared_to_project", ip.shared_to_project),
        ("deleted", ip.deleted),
        ("created", ip.created),
        ("updated", ip.updated),
    ])

    pprint_table(stdout, vtype_info.items(), separator=" | ", title=title)
Beispiel #11
0
def project_fields(project):
    app = project.last_application
    pending_app = (app.id if app and app.state == app.PENDING
                   else None)

    d = OrderedDict([
        ('project id', project.uuid),
        ('name', project.realname),
        ('status', project.state_display()),
        ('pending_app', pending_app),
        ('owner', project.owner),
        ('homepage', project.homepage),
        ('description', project.description),
        ('creation date', project.creation_date),
        ('request end date', project.end_date),
        ])

    deact = project.last_deactivation()
    if deact is not None:
        d['deactivation date'] = deact.date

    d.update([
            ('join policy', project.member_join_policy_display),
            ('leave policy', project.member_leave_policy_display),
            ('max members', units.show(project.limit_on_members_number, None)),
            ('total members', project.members_count()),
    ])

    return d
Beispiel #12
0
def pprint_floating_ip(ip, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Floating IP %s" % ip.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = ip.userid

    vtype_info = OrderedDict([
        ("id", ip.id),
        ("address", ip.address),
        ("network", ip.network_id),
        ("port", ip.nic_id),
        ("server", ip.nic.machine_id),
        ("userid", userid),
        ("username", ucache.get_name(userid) if (display_mails and userid is
                                                 not None) else None),
        ("project", ip.project),
        ("shared_to_project", ip.shared_to_project),
        ("deleted", ip.deleted),
        ("created", ip.created),
        ("updated", ip.updated),
    ])

    pprint_table(stdout, vtype_info.items(), separator=" | ", title=title)
Beispiel #13
0
def pprint_server_in_ganeti(server, print_jobs=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Server %s in Ganeti" % server.id

    client = server.get_client()
    try:
        server_info = client.GetInstance(server.backend_vm_id)
    except GanetiApiError as e:
        if e.code == 404:
            stdout.write("Server '%s' does not exist in backend '%s'\n" %
                         (server.id, server.backend.clustername))
            return
        raise e
    server.put_client(client)

    GANETI_INSTANCE_FIELDS = ('name', 'oper_state', 'admin_state', 'status',
                              'pnode', 'snode', 'network_port',
                              'disk_template', 'disk_usage', 'oper_ram',
                              'oper_vcpus', 'mtime')
    server_dict = OrderedDict([(k, server_info.get(k))
                               for k in GANETI_INSTANCE_FIELDS])

    pprint_table(stdout,
                 server_dict.items(),
                 None,
                 separator=" | ",
                 title=title)
    stdout.write("\n")

    nics = nics_from_instance(server_info)
    nics_keys = ["ip", "mac", "name", "network"]
    nics_values = [[nic[key] for key in nics_keys] for nic in nics]
    pprint_table(stdout,
                 nics_values,
                 nics_keys,
                 separator=" | ",
                 title="NICs of Server %s in Ganeti" % server.id)

    if not print_jobs:
        return

    client = server.get_client()
    jobs = client.GetJobs(bulk=True)
    server_jobs = filter(
        lambda x: server.backend_vm_id in (" ".join(x.get("summary"))), jobs)

    GANETI_JOB_FIELDS = ('id', 'status', 'summary', 'opresult', 'opstatus',
                         'oplog', 'start_ts', 'end_ts')
    for server_job in server_jobs:
        stdout.write("\n")
        values = [server_job.get(k) for k in GANETI_JOB_FIELDS]
        pprint_table(stdout,
                     zip(GANETI_JOB_FIELDS, values),
                     None,
                     separator=" | ",
                     title="Ganeti Job %s" % server_job["id"])
    server.put_client(client)
Beispiel #14
0
def pprint_server_in_ganeti(server, print_jobs=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Server %s in Ganeti" % server.id

    client = server.get_client()
    try:
        server_info = client.GetInstance(server.backend_vm_id)
    except GanetiApiError as e:
        if e.code == 404:
            stdout.write("Server '%s' does not exist in backend '%s'\n"
                         % (server.id, server.backend.clustername))
            return
        raise e
    server.put_client(client)

    GANETI_INSTANCE_FIELDS = ('name', 'oper_state', 'admin_state', 'status',
                              'pnode', 'snode', 'network_port',
                              'disk_template', 'disk_usage',
                              'oper_ram', 'oper_vcpus', 'mtime')
    server_dict = OrderedDict([(k, server_info.get(k))
                              for k in GANETI_INSTANCE_FIELDS])

    pprint_table(stdout, server_dict.items(), None, separator=" | ",
                 title=title)
    stdout.write("\n")

    nics = nics_from_instance(server_info)
    nics_keys = ["ip", "mac", "name", "network"]
    nics_values = [[nic[key] for key in nics_keys] for nic in nics]
    pprint_table(stdout, nics_values, nics_keys, separator=" | ",
                 title="NICs of Server %s in Ganeti" % server.id)

    stdout.write("\n")
    disks = disks_from_instance(server_info)
    disks_keys = ["name", "size"]
    disks_values = [[disk[key] for key in disks_keys] for disk in disks]
    pprint_table(stdout, disks_values, disks_keys, separator=" | ",
                 title="Disks of Server %s in Ganeti" % server.id)

    if not print_jobs:
        return

    client = server.get_client()
    jobs = client.GetJobs(bulk=True)
    server_jobs = filter(
        lambda x: server.backend_vm_id in (" ".join(x.get("summary"))), jobs)

    GANETI_JOB_FIELDS = ('id', 'status', 'summary', 'opresult', 'opstatus',
                         'oplog', 'start_ts', 'end_ts')
    for server_job in server_jobs:
        stdout.write("\n")
        values = [server_job.get(k) for k in GANETI_JOB_FIELDS]
        pprint_table(stdout, zip(GANETI_JOB_FIELDS, values), None,
                     separator=" | ",
                     title="Ganeti Job %s" % server_job["id"])
    server.put_client(client)
Beispiel #15
0
def pprint_port(port, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Port %s in DB" % port.id
    port = OrderedDict([("id", port.id), ("name", port.name),
                        ("userid", port.userid), ("server", port.machine_id),
                        ("network", port.network_id),
                        ("device_owner", port.device_owner), ("mac", port.mac),
                        ("state", port.state)])

    pprint_table(stdout, port.items(), None, separator=" | ", title=title)
Beispiel #16
0
    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies['automoderate'] = not \
            astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True
Beispiel #17
0
def pprint_volume_type(volume_type, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Volume Type %s" % volume_type.id

    vtype_info = OrderedDict([
        ("name", volume_type.name),
        ("disk template", volume_type.disk_template),
        ("deleted", volume_type.deleted),
    ])

    pprint_table(stdout, vtype_info.items(), separator=" | ", title=title)
Beispiel #18
0
def pprint_volume_type(volume_type, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Volume Type %s" % volume_type.id

    vtype_info = OrderedDict([
        ("name", volume_type.name),
        ("disk template", volume_type.disk_template),
        ("deleted", volume_type.deleted),
    ])

    pprint_table(stdout, vtype_info.items(), separator=" | ", title=title)
Beispiel #19
0
    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True
Beispiel #20
0
def pprint_volume_type(volume_type, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Volume Type %s" % volume_type.id

    specs_str = ", ".join(str(s) for s in volume_type.specs.all())
    vtype_info = OrderedDict([
        ("name", volume_type.name),
        ("disk template", volume_type.disk_template),
        ("deleted", volume_type.deleted),
        ("specs", specs_str),
    ])

    pprint_table(stdout, vtype_info.items(), separator=" | ", title=title)
Beispiel #21
0
    def __init__(self,
                 hosts=settings.AMQP_HOSTS,
                 max_retries=30,
                 confirms=True,
                 confirm_buffer=200):
        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
Beispiel #22
0
def handle_destroy(viol_id,
                   resource,
                   vms,
                   diff,
                   actions,
                   remains,
                   options=None):
    cascade_remove = options.get("cascade_remove", False)
    vm_actions = actions["vm"]
    if "volume" not in actions:
        actions["volume"] = OrderedDict()
    volume_actions = actions["volume"]
    vms = sorted(vms, key=sort_vms(), reverse=True)
    all_volumes = Volume.objects.filter(deleted=False, machine__in=vms)
    all_volumes = _partition_by(lambda vol: vol.machine_id, all_volumes)
    for vm in vms:
        if diff < 1:
            break
        volumes = all_volumes.get(vm.id, [])
        if has_extra_disks(volumes) and not cascade_remove:
            continue
        diff -= CHANGE[resource](vm)
        vm_actions[vm.id] = vm_remove_action(viol_id, vm)
        for volume in volumes:
            volume_actions[volume.id] = volume_remove_action(viol_id,
                                                             volume,
                                                             machine=vm)
    if diff > 0:
        remains[resource].append(viol_id)
Beispiel #23
0
def app_fields(app):
    d = OrderedDict([
        ('project id', app.chain.uuid),
        ('application id', app.id),
        ('status', app.state_display()),
        ('applicant', app.applicant),
        ('comments for review', app.comments),
        ('request issue date', app.issue_date),
    ])
    if app.name:
        d['name'] = app.name
    if app.owner:
        d['owner'] = app.owner
    if app.homepage:
        d['homepage'] = app.homepage
    if app.description:
        d['description'] = app.description
    if app.start_date:
        d['request start date'] = app.start_date
    if app.end_date:
        d['request end date'] = app.end_date
    if app.member_join_policy:
        d['join policy'] = app.member_join_policy_display
    if app.member_leave_policy:
        d['leave policy'] = app.member_leave_policy_display
    if app.limit_on_members_number:
        d['max members'] = units.show(app.limit_on_members_number, None)

    return d
Beispiel #24
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please provide a component name or ID.")

        identifier = args[0]
        if identifier.isdigit():
            try:
                component = Component.objects.get(id=int(identifier))
            except Component.DoesNotExist:
                raise CommandError('No component found with ID %s.' %
                                   identifier)
        else:
            try:
                component = Component.objects.get(name=identifier)
            except Component.DoesNotExist:
                raise CommandError('No component found named %s.' % identifier)

        kv = OrderedDict([
            ('id', component.id),
            ('name', component.name),
            ('base url', component.base_url),
            ('ui url', component.url),
            ('token', component.auth_token),
            ('token created', component.auth_token_created),
            ('token expires', component.auth_token_expires),
        ])

        utils.pprint_table(self.stdout, [kv.values()],
                           kv.keys(),
                           options["output_format"],
                           vertical=True)

        services = component.service_set.all()

        service_data = []
        for service in services:
            service_data.append((service.id, service.name, service.type))

        if service_data:
            self.stdout.write('\n')
            labels = ('id', 'name', 'type')
            utils.pprint_table(self.stdout,
                               service_data,
                               labels,
                               options["output_format"],
                               title='Registered services')
Beispiel #25
0
def pprint_port(port, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Port %s in DB" % port.id
    port = OrderedDict([
        ("id", port.id),
        ("name", port.name),
        ("userid", port.userid),
        ("server", port.machine_id),
        ("network", port.network_id),
        ("device_owner", port.device_owner),
        ("mac", port.mac),
        ("state", port.state)])

    pprint_table(stdout, port.items(), None, separator=" | ",
                 title=title)
Beispiel #26
0
def pprint_server(server, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Server %s in DB" % server.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = server.userid

    try:
        image = get_image(server.imageid, server.userid)['name']
    except:
        image = server.imageid

    server_dict = OrderedDict([
        ("id", server.id),
        ("name", server.name),
        ("userid", server.userid),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("project", server.project),
        ("shared_to_project", server.shared_to_project),
        ("flavor_id", server.flavor_id),
        ("flavor_name", server.flavor.name),
        ("imageid", server.imageid),
        ("image_name", image),
        ("created", server.created),
        ("state", server.operstate),
        ("backend", server.backend),
        ("deleted", server.deleted),
        ("action", server.action),
        ("task", server.task),
        ("rescue", server.rescue),
        ("rescue_image", server.rescue_image),
        ("task_job_id", server.task_job_id),
        ("backendjobid", server.backendjobid),
        ("backendopcode", server.backendopcode),
        ("backendjobstatus", server.backendjobstatus),
        ("backend_time", server.backendtime),
    ])

    pprint_table(stdout,
                 server_dict.items(),
                 None,
                 separator=" | ",
                 title=title)
Beispiel #27
0
def pprint_subnet_in_db(subnet, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Subnet %s in DB" % subnet.id
    info = OrderedDict([("ID", subnet.id),
                        ("Network_ID", subnet.network.id),
                        # If a user names his subnet "-", what happens then?
                        ("User_ID", subnet.userid),
                        ("Name", "-" if subnet.name == "" else subnet.name),
                        ("IP_Version", subnet.ipversion),
                        ("CIDR", subnet.cidr),
                        ("Gateway", subnet.gateway),
                        ("Public", subnet.public),
                        ("DHCP/SLAAC", subnet.dhcp),
                        ("Host_Routes", subnet.host_routes),
                        ("DNS_Nameservers", subnet.dns_nameservers)])
    pprint_table(stdout, info.items(), None, separator=" | ", title=title)
Beispiel #28
0
def pprint_port(port, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Port %s in DB" % port.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = port.userid

    port = OrderedDict([("id", port.id), ("name", port.name),
                        ("userid", port.userid),
                        ("username",
                         ucache.get_name(userid) if display_mails else None),
                        ("server", port.machine_id),
                        ("network", port.network_id),
                        ("device_owner", port.device_owner), ("mac", port.mac),
                        ("state", port.state)])

    pprint_table(stdout, port.items(), None, separator=" | ", title=title)
Beispiel #29
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please provide a component name or ID.")

        identifier = args[0]
        if identifier.isdigit():
            try:
                component = Component.objects.get(id=int(identifier))
            except Component.DoesNotExist:
                raise CommandError('No component found with ID %s.' %
                                   identifier)
        else:
            try:
                component = Component.objects.get(name=identifier)
            except Component.DoesNotExist:
                raise CommandError('No component found named %s.' % identifier)

        kv = OrderedDict(
            [
                ('id', component.id),
                ('name', component.name),
                ('base url', component.base_url),
                ('ui url', component.url),
                ('token', component.auth_token),
                ('token created', component.auth_token_created),
                ('token expires', component.auth_token_expires),
            ])

        utils.pprint_table(self.stdout, [kv.values()], kv.keys(),
                           options["output_format"], vertical=True)

        services = component.service_set.all()

        service_data = []
        for service in services:
            service_data.append((service.id, service.name, service.type))

        if service_data:
            self.stdout.write('\n')
            labels = ('id', 'name', 'type')
            utils.pprint_table(self.stdout, service_data, labels,
                               options["output_format"],
                               title='Registered services')
Beispiel #30
0
def handle_volume(viol_id,
                  resource,
                  volumes,
                  diff,
                  actions,
                  remains,
                  options=None):
    if "vm" not in actions:
        actions["vm"] = OrderedDict()
    vm_actions = actions["vm"]
    volume_actions = actions["volume"]
    remove_system_volumes = options.get("remove_system_volumes", False)
    cascade_remove = options.get("cascade_remove", False)
    other_removed = set(volume_actions.keys())
    volumes = sorted(volumes, key=sort_volumes(other_removed), reverse=True)
    volume_ids = set(vol.id for vol in volumes)
    machines = set(volume.machine_id for volume in volumes)
    all_volumes = Volume.objects.filter(deleted=False, machine__in=machines)
    all_volumes = _partition_by(lambda vol: vol.machine_id, all_volumes)
    counted = set()

    for volume in volumes:
        if diff < 1:
            break
        if volume.id in counted:
            continue
        if volume.id in other_removed:
            diff -= CHANGE[resource](volume)
            counted.add(volume.id)
            continue
        if not remove_system_volumes and _is_system_volume(volume):
            continue
        if not _is_system_volume(volume):
            diff -= CHANGE[resource](volume)
            volume_actions[volume.id] = volume_remove_action(viol_id, volume)
            counted.add(volume)
            continue
        vm = volume.machine
        sec_volumes = [
            v for v in all_volumes.get(vm.id, []) if v.id != volume.id
        ]
        if sec_volumes and not cascade_remove:
            continue
        volume_actions[volume.id] = volume_remove_action(viol_id, volume)
        diff -= CHANGE[resource](volume)
        counted.add(volume)
        vm_actions[vm.id] = vm_remove_action(viol_id, vm)
        for vol in sec_volumes:
            volume_actions[vol.id] = volume_remove_action(viol_id, vol)
            if vol.id in volume_ids and vol.id not in counted:
                diff -= CHANGE[resource](vol)
                counted.add(vol.id)
    if diff > 0:
        remains[resource].append(viol_id)
Beispiel #31
0
def pprint_subnet_in_db(subnet, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Subnet %s in DB" % subnet.id
    info = OrderedDict([
        ("ID", subnet.id),
        ("Network_ID", subnet.network.id),
        # If a user names his subnet "-", what happens then?
        ("User_ID", subnet.userid),
        ("Name", "-" if subnet.name == "" else subnet.name),
        ("IP_Version", subnet.ipversion),
        ("CIDR", subnet.cidr),
        ("Gateway", subnet.gateway),
        ("Public", subnet.public),
        ("DHCP/SLAAC", subnet.dhcp),
        ("Host_Routes", subnet.host_routes),
        ("DNS_Nameservers", subnet.dns_nameservers)
    ])
    pprint_table(stdout, info.items(), None, separator=" | ", title=title)
Beispiel #32
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please profile name")

        try:
            profile = Profile.objects.get(name=args[0])
        except Profile.DoesNotExist:
            raise CommandError("Profile does not exist")

        kv = OrderedDict([('id', profile.id),
                          ('is active', str(profile.active)),
                          ('name', profile.name),
                          ('is exclusive', profile.is_exclusive),
                          ('policies', profile.policies),
                          ('groups', profile.groups.all()),
                          ('users', profile.users.all())])

        utils.pprint_table(self.stdout, [kv.values()],
                           kv.keys(),
                           options["output_format"],
                           vertical=True)
Beispiel #33
0
def pprint_server(server, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Server %s in DB" % server.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = server.userid

    try:
        image = get_image(server.imageid, server.userid)['name']
    except:
        image = server.imageid

    server_dict = OrderedDict([
        ("id", server.id),
        ("name", server.name),
        ("userid", server.userid),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("project", server.project),
        ("shared_to_project", server.shared_to_project),
        ("flavor_id", server.flavor_id),
        ("flavor_name", server.flavor.name),
        ("imageid", server.imageid),
        ("image_name", image),
        ("created", server.created),
        ("state", server.operstate),
        ("backend", server.backend),
        ("deleted", server.deleted),
        ("action", server.action),
        ("task", server.task),
        ("task_job_id", server.task_job_id),
        ("backendjobid", server.backendjobid),
        ("backendopcode", server.backendopcode),
        ("backendjobstatus", server.backendjobstatus),
        ("backend_time", server.backendtime),
        ])

    pprint_table(stdout, server_dict.items(), None, separator=" | ",
                 title=title)
Beispiel #34
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please provide a service name or ID.")

        identifier = args[0]
        if identifier.isdigit():
            try:
                service = Service.objects.get(id=int(identifier))
            except Service.DoesNotExist:
                raise CommandError('No service found with ID %s.' % identifier)
        else:
            try:
                service = Service.objects.get(name=identifier)
            except Service.DoesNotExist:
                raise CommandError('No service found named %s.' % identifier)

        kv = OrderedDict([
            ('id', service.id),
            ('name', service.name),
            ('component', service.component),
            ('type', service.type),
        ])

        utils.pprint_table(self.stdout, [kv.values()],
                           kv.keys(),
                           options["output_format"],
                           vertical=True)

        self.stdout.write('\n')
        endpoint_data = EndpointData.objects.filter(endpoint__service=service)
        data = []
        for ed in endpoint_data:
            data.append((ed.endpoint_id, ed.key, ed.value))

        labels = ('endpoint', 'key', 'value')
        utils.pprint_table(self.stdout,
                           data,
                           labels,
                           options["output_format"],
                           title='Endpoints')
Beispiel #35
0
def pprint_flavor(flavor, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "Flavor %s" % flavor.name

    flavor_specs = ', '.join([str(spec) for spec in flavor.specs.all()])

    flavor_info = OrderedDict([
        ("id", flavor.id),
        ("name", flavor.name),
        ("cpu", flavor.cpu),
        ("ram", flavor.ram),
        ("disk", flavor.disk),
        ("volume_type", flavor.volume_type_id),
        ("template", flavor.volume_type.disk_template),
        ("allow_create", flavor.allow_create),
        ("public", flavor.public),
        ("specs", flavor_specs),
    ])

    pprint_table(stdout, flavor_info.items(), separator=" | ", title=title)
Beispiel #36
0
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=200):
        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
Beispiel #37
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please profile name")

        try:
            profile = Profile.objects.get(name=args[0])
        except Profile.DoesNotExist:
            raise CommandError("Profile does not exist")

        kv = OrderedDict(
            [
                ('id', profile.id),
                ('is active', str(profile.active)),
                ('name', profile.name),
                ('is exclusive', profile.is_exclusive),
                ('policies', profile.policies),
                ('groups', profile.groups.all()),
                ('users', profile.users.all())
            ])

        utils.pprint_table(self.stdout, [kv.values()], kv.keys(),
                           options["output_format"], vertical=True)
Beispiel #38
0
def pprint_port(port, display_mails=False, stdout=None, title=None):
    if stdout is None:
        stdout = sys.stdout
    if title is None:
        title = "State of Port %s in DB" % port.id

    ucache = UserCache(ASTAKOS_AUTH_URL, ASTAKOS_TOKEN)
    userid = port.userid

    port = OrderedDict([
        ("id", port.id),
        ("name", port.name),
        ("userid", port.userid),
        ("username", ucache.get_name(userid) if display_mails else None),
        ("server", port.machine_id),
        ("network", port.network_id),
        ("device_owner", port.device_owner),
        ("mac", port.mac),
        ("state", port.state)])

    pprint_table(stdout, port.items(), None, separator=" | ",
                 title=title)
Beispiel #39
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please provide a service name or ID.")

        identifier = args[0]
        if identifier.isdigit():
            try:
                service = Service.objects.get(id=int(identifier))
            except Service.DoesNotExist:
                raise CommandError('No service found with ID %s.' % identifier)
        else:
            try:
                service = Service.objects.get(name=identifier)
            except Service.DoesNotExist:
                raise CommandError('No service found named %s.' % identifier)

        kv = OrderedDict(
            [
                ('id', service.id),
                ('name', service.name),
                ('component', service.component),
                ('type', service.type),
            ])

        utils.pprint_table(self.stdout, [kv.values()], kv.keys(),
                           options["output_format"], vertical=True)

        self.stdout.write('\n')
        endpoint_data = EndpointData.objects.filter(endpoint__service=service)
        data = []
        for ed in endpoint_data:
            data.append((ed.endpoint_id, ed.key, ed.value))

        labels = ('endpoint', 'key', 'value')
        utils.pprint_table(self.stdout, data, labels,
                           options["output_format"],
                           title='Endpoints')
Beispiel #40
0
def project_fields(project, pending_app):
    app = project.application

    d = OrderedDict([
        ('project id', project.id),
        ('application id', app.id),
        ('name', app.name),
        ('status', project.state_display()),
    ])
    if pending_app is not None:
        d.update([('pending application', pending_app.id)])

    d.update([
        ('owner', app.owner),
        ('applicant', app.applicant),
        ('homepage', app.homepage),
        ('description', app.description),
        ('comments for review', app.comments),
        ('request issue date', app.issue_date),
        ('request start date', app.start_date),
        ('creation date', project.creation_date),
        ('request end date', app.end_date),
    ])

    deact = project.last_deactivation()
    if deact is not None:
        d['deactivation date'] = deact.date

    mem_limit = app.limit_on_members_number
    mem_limit_show = mem_limit if mem_limit is not None else "unlimited"

    d.update([
        ('join policy', app.member_join_policy_display),
        ('leave policy', app.member_leave_policy_display),
        ('max members', mem_limit_show),
        ('total members', project.members_count()),
    ])

    return d
def app_fields(app):
    mem_limit = app.limit_on_members_number
    mem_limit_show = mem_limit if mem_limit is not None else "unlimited"

    d = OrderedDict([
        ('project id', app.chain),
        ('application id', app.id),
        ('name', app.name),
        ('status', app.state_display()),
        ('owner', app.owner),
        ('applicant', app.applicant),
        ('homepage', app.homepage),
        ('description', app.description),
        ('comments for review', app.comments),
        ('request issue date', app.issue_date),
        ('request start date', app.start_date),
        ('request end date', app.end_date),
        ('join policy', app.member_join_policy_display),
        ('leave policy', app.member_leave_policy_display),
        ('max members', mem_limit_show),
    ])

    return d
Beispiel #42
0
def project_fields(s, project, last_app):
    app = project.application

    d = OrderedDict(
        [("project id", project.id), ("application id", app.id), ("name", app.name), ("status", Chain.state_display(s))]
    )
    if s in Chain.PENDING_STATES:
        d.update([("pending application", last_app.id)])

    d.update(
        [
            ("owner", app.owner),
            ("applicant", app.applicant),
            ("homepage", app.homepage),
            ("description", app.description),
            ("comments for review", app.comments),
            ("request issue date", app.issue_date),
            ("request start date", app.start_date),
            ("creation date", project.creation_date),
            ("request end date", app.end_date),
        ]
    )

    deact_date = project.deactivation_date
    if deact_date is not None:
        d["deactivation date"] = deact_date

    mem_limit = app.limit_on_members_number
    mem_limit_show = mem_limit if mem_limit is not None else "unlimited"

    d.update(
        [
            ("join policy", app.member_join_policy_display),
            ("leave policy", app.member_leave_policy_display),
            ("max members", mem_limit_show),
            ("total members", project.members_count()),
        ]
    )

    return d
Beispiel #43
0
def project_fields(project, pending_app):
    app = project.application

    d = OrderedDict([
        ('project id', project.id),
        ('application id', app.id),
        ('name', app.name),
        ('status', project.state_display()),
    ])
    if pending_app is not None:
        d.update([('pending application', pending_app.id)])

    d.update([('owner', app.owner),
              ('applicant', app.applicant),
              ('homepage', app.homepage),
              ('description', app.description),
              ('comments for review', app.comments),
              ('request issue date', app.issue_date),
              ('request start date', app.start_date),
              ('creation date', project.creation_date),
              ('request end date', app.end_date),
              ])

    deact = project.last_deactivation()
    if deact is not None:
        d['deactivation date'] = deact.date

    mem_limit = app.limit_on_members_number
    mem_limit_show = mem_limit if mem_limit is not None else "unlimited"

    d.update([
            ('join policy', app.member_join_policy_display),
            ('leave policy', app.member_leave_policy_display),
            ('max members', mem_limit_show),
            ('total members', project.members_count()),
    ])

    return d
Beispiel #44
0
class AMQPHaighaClient():
    def __init__(self,
                 hosts=settings.AMQP_HOSTS,
                 max_retries=30,
                 confirms=True,
                 confirm_buffer=200):
        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()

    def connect(self):
        """Initialize a connection with the AMQP server. If it fails, retry at
        most <max_retries> times.
        """

        # Patch gevent
        monkey.patch_all()

        retries = 0
        self.connection = None

        # Try to connect at most <max_retries> times
        while self.max_retries == 0 or retries < self.max_retries:
            retries += 1
            # Pick up a host
            host = self.hosts.pop()
            self.hosts.insert(0, host)
            try:
                self.connection = RabbitConnection(logger=logger,
                                                   debug=True,
                                                   user='******',
                                                   password='******',
                                                   vhost='/',
                                                   host=host,
                                                   heartbeat=None,
                                                   sock_opts=sock_opts,
                                                   transport='gevent')
                break
            except socket.error as e:
                self.connection = None
                logger.error('Cannot connect to host %s: %s', host, e)
                if retries > 2 * len(self.hosts):
                    sleep(1)

        if not self.connection:
            raise AMQPConnectionError(
                'Aborting after %d connection failures!' % self.max_retries)

        logger.info('Successfully connected to host: %s', host)

        logger.info('Creating channel')
        self.channel = self.connection.channel()

        if self.confirms:
            self._confirm_select()

        if self.unacked:
            self._resend_unacked_messages()

        if self.consumers:
            for queue, callback in self.consumers.items():
                self.basic_consume(queue, callback)

    def exchange_declare(self, exchange, type='direct'):
        """Declare an exchange
        @type exchange_name: string
        @param exchange_name: name of the exchange
        @type exchange_type: string
        @param exhange_type: one of 'direct', 'topic', 'fanout'

        """

        logger.info('Declaring %s exchange: %s', type, exchange)
        self.channel.exchange.declare(exchange,
                                      type,
                                      auto_delete=False,
                                      durable=True)

    def queue_declare(self,
                      queue,
                      exclusive=False,
                      mirrored=True,
                      mirrored_nodes='all',
                      ttl=None):
        """Declare a queue

        @type queue: string
        @param queue: name of the queue
        @param mirrored: whether the queue will be mirrored to other brokers
        @param mirrored_nodes: the policy for the mirrored queue.
            Available policies:
                - 'all': The queue is mirrored to all nodes and the
                  master node is the one to which the client is
                  connected
                - a list of nodes. The queue will be mirrored only to
                  the specified nodes, and the master will be the
                  first node in the list. Node names must be provided
                  and not host IP. example: [node1@rabbit,node2@rabbit]
        @type ttl: int
        @param tll: Queue TTL in seconds

        """

        logger.info('Declaring queue: %s', queue)
        if mirrored:
            if mirrored_nodes == 'all':
                arguments = {'x-ha-policy': 'all'}
            elif isinstance(mirrored_nodes, list):
                arguments = {
                    'x-ha-policy': 'nodes',
                    'x-ha-policy-params': mirrored_nodes
                }
            else:
                raise AttributeError
        else:
            arguments = {}

        if ttl is not None:
            arguments['x-expires'] = ttl * 1000

        self.channel.queue.declare(queue,
                                   durable=True,
                                   exclusive=exclusive,
                                   auto_delete=False,
                                   arguments=arguments)

    def queue_bind(self, queue, exchange, routing_key):
        logger.info('Binding queue %s to exchange %s with key %s', queue,
                    exchange, routing_key)
        self.channel.queue.bind(queue=queue,
                                exchange=exchange,
                                routing_key=routing_key)

    def _confirm_select(self):
        logger.info('Setting channel to confirm mode')
        self.channel.confirm.select()
        self.channel.basic.set_ack_listener(self._ack_received)
        self.channel.basic.set_nack_listener(self._nack_received)

    @reconnect_decorator
    def basic_publish(self, exchange, routing_key, body):
        msg = Message(body, delivery_mode=2)
        mid = self.channel.basic.publish(msg, exchange, routing_key)
        if self.confirms:
            self.unacked[mid] = (exchange, routing_key, body)
            if len(self.unacked) > self.confirm_buffer:
                self.get_confirms()

        logger.debug('Published message %s with id %s', body, mid)

    @reconnect_decorator
    def get_confirms(self):
        self.connection.read_frames()

    @reconnect_decorator
    def _resend_unacked_messages(self):
        msgs = self.unacked.values()
        self.unacked.clear()
        for exchange, routing_key, body in msgs:
            logger.debug('Resending message %s', body)
            self.basic_publish(exchange, routing_key, body)

    @reconnect_decorator
    def _ack_received(self, mid):
        print mid
        logger.debug('Received ACK for message with id %s', mid)
        self.unacked.pop(mid)

    @reconnect_decorator
    def _nack_received(self, mid):
        logger.error('Received NACK for message with id %s. Retrying.', mid)
        (exchange, routing_key, body) = self.unacked[mid]
        self.basic_publish(exchange, routing_key, body)

    def basic_consume(self, queue, callback, no_ack=False, exclusive=False):
        """Consume from a queue.

        @type queue: string or list of strings
        @param queue: the name or list of names from the queues to consume
        @type callback: function
        @param callback: the callback function to run when a message arrives

        """

        self.consumers[queue] = callback
        self.channel.basic.consume(queue,
                                   consumer=callback,
                                   no_ack=no_ack,
                                   exclusive=exclusive)

    @reconnect_decorator
    def basic_wait(self):
        """Wait for messages from the queues declared by basic_consume.

        This function will block until a message arrives from the queues that
        have been declared with basic_consume. If the optional arguments
        'promise' is given, only messages for this promise will be delivered.

        """

        self.connection.read_frames()
        gevent.sleep(0)

    @reconnect_decorator
    def basic_get(self, queue, no_ack=False):
        self.channel.basic.get(queue, no_ack=no_ack)

    @reconnect_decorator
    def basic_ack(self, message):
        delivery_tag = message.delivery_info['delivery_tag']
        self.channel.basic.ack(delivery_tag)

    @reconnect_decorator
    def basic_nack(self, message):
        delivery_tag = message.delivery_info['delivery_tag']
        self.channel.basic.ack(delivery_tag)

    def close(self):
        try:
            if self.confirms:
                while self.unacked:
                    print self.unacked
                    self.get_confirms()
            self.channel.close()
            close_info = self.channel.close_info
            logger.info('Successfully closed channel. Info: %s', close_info)
            self.connection.close()
        except socket.error as e:
            logger.error('Connection closed while closing connection:%s', e)

    def queue_delete(self, queue, if_unused=True, if_empty=True):
        self.channel.queue.delete(queue, if_unused, if_empty)

    def exchange_delete(self, exchange, if_unused=True):
        self.channel.exchange.delete(exchange, if_unused)

    def basic_class(self):
        pass
Beispiel #45
0
def _resources_catalog(as_dict=False):
    """
    `resource_catalog` contains a list of tuples. Each tuple contains the group
    key the resource is assigned to and resources list of dicts that contain
    resource information.
    `resource_groups` contains information about the groups
    """
    # presentation data
    resources_meta = presentation.RESOURCES
    resource_groups = resources_meta.get('groups', {})
    resource_catalog = ()
    resource_keys = []

    # resources in database
    resource_details = map(lambda obj: model_to_dict(obj, exclude=[]),
                           Resource.objects.all())
    # initialize resource_catalog to contain all group/resource information
    for r in resource_details:
        if not r.get('group') in resource_groups:
            resource_groups[r.get('group')] = {'icon': 'unknown'}

    resource_keys = [r.get('str_repr') for r in resource_details]
    resource_catalog = [[
        g, filter(lambda r: r.get('group', '') == g, resource_details)
    ] for g in resource_groups]

    # order groups, also include unknown groups
    groups_order = resources_meta.get('groups_order')
    for g in resource_groups.keys():
        if not g in groups_order:
            groups_order.append(g)

    # order resources, also include unknown resources
    resources_order = resources_meta.get('resources_order')
    for r in resource_keys:
        if not r in resources_order:
            resources_order.append(r)

    # sort catalog groups
    resource_catalog = sorted(resource_catalog,
                              key=lambda g: groups_order.index(g[0]))

    # sort groups
    def groupindex(g):
        return groups_order.index(g[0])

    resource_groups_list = sorted([(k, v) for k, v in resource_groups.items()],
                                  key=groupindex)
    resource_groups = OrderedDict(resource_groups_list)

    # sort resources
    def resourceindex(r):
        return resources_order.index(r['str_repr'])

    for index, group in enumerate(resource_catalog):
        resource_catalog[index][1] = sorted(resource_catalog[index][1],
                                            key=resourceindex)
        if len(resource_catalog[index][1]) == 0:
            resource_catalog.pop(index)
            for gindex, g in enumerate(resource_groups):
                if g[0] == group[0]:
                    resource_groups.pop(gindex)

    # filter out resources which user cannot request in a project application
    for group, resources in list(resource_catalog):
        for resource in resources:
            if not resource.get('ui_visible'):
                resources.remove(resource)

    # cleanup empty groups
    resource_catalog_new = []
    for group, resources in list(resource_catalog):
        if len(resources) == 0:
            resource_groups.pop(group)
        else:
            resource_catalog_new.append((group, resources))

    if as_dict:
        resource_catalog_new = OrderedDict(resource_catalog_new)
        for name, resources in resource_catalog_new.iteritems():
            _rs = OrderedDict()
            for resource in resources:
                _rs[resource.get('name')] = resource
            resource_catalog_new[name] = _rs
        resource_groups = OrderedDict(resource_groups)

    return resource_catalog_new, resource_groups
Beispiel #46
0
def _resources_catalog():
    """
    `resource_catalog` contains a list of tuples. Each tuple contains the group
    key the resource is assigned to and resources list of dicts that contain
    resource information.
    `resource_groups` contains information about the groups
    """
    # presentation data
    resources_meta = presentation.RESOURCES
    resource_groups = resources_meta.get('groups', {})
    resource_catalog = ()
    resource_keys = []

    # resources in database
    resource_details = map(lambda obj: model_to_dict(obj, exclude=[]),
                           Resource.objects.all())
    # initialize resource_catalog to contain all group/resource information
    for r in resource_details:
        if not r.get('group') in resource_groups:
            resource_groups[r.get('group')] = {'icon': 'unknown'}

    resource_keys = [r.get('str_repr') for r in resource_details]
    resource_catalog = [[g, filter(lambda r: r.get('group', '') == g,
                                   resource_details)] for g in resource_groups]

    # order groups, also include unknown groups
    groups_order = resources_meta.get('groups_order')
    for g in resource_groups.keys():
        if not g in groups_order:
            groups_order.append(g)

    # order resources, also include unknown resources
    resources_order = resources_meta.get('resources_order')
    for r in resource_keys:
        if not r in resources_order:
            resources_order.append(r)

    # sort catalog groups
    resource_catalog = sorted(resource_catalog,
                              key=lambda g: groups_order.index(g[0]))

    # sort groups
    def groupindex(g):
        return groups_order.index(g[0])
    resource_groups_list = sorted([(k, v) for k, v in resource_groups.items()],
                                  key=groupindex)
    resource_groups = OrderedDict(resource_groups_list)

    # sort resources
    def resourceindex(r):
        return resources_order.index(r['str_repr'])

    for index, group in enumerate(resource_catalog):
        resource_catalog[index][1] = sorted(resource_catalog[index][1],
                                            key=resourceindex)
        if len(resource_catalog[index][1]) == 0:
            resource_catalog.pop(index)
            for gindex, g in enumerate(resource_groups):
                if g[0] == group[0]:
                    resource_groups.pop(gindex)

    # filter out resources which user cannot request in a project application
    for group, resources in list(resource_catalog):
        for resource in resources:
            if not resource.get('ui_visible'):
                resources.remove(resource)

    # cleanup empty groups
    resource_catalog_new = []
    for group, resources in list(resource_catalog):
        if len(resources) == 0:
            resource_groups.pop(group)
        else:
            resource_catalog_new.append((group, resources))
    return resource_catalog_new, resource_groups
Beispiel #47
0
def parse(s):
    n, _ = parse_with_style(s)
    return n


UNITS = {
    'bytes': {
        'DISPLAY': ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'],
        'BASE': 1024,
    }
}

STYLE_TO_EXP = OrderedDict([
    ('b', 0),
    ('kb', 1),
    ('mb', 2),
    ('gb', 3),
    ('tb', 4),
    ('pb', 5),
])

STYLES = STYLE_TO_EXP.keys() + ['auto', 'none']


class StyleError(Exception):
    pass


def show_float(n):
    if n < 1:
        return "%.3f" % n
    if n < 10:
Beispiel #48
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using {account_prompt}'),
        ('required', '{title} is required. You can assign it '
         'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
         'trying to access {service_name}. '
         'Unfortunately, we are not accepting new '
         'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
         'Please use one of your other available methods '
         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png')))

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'mirror_groups': False,  # Currently used only by LDAP
        'required': False,
        'autoverify': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    # Mapping of provider's attributes to attributes of AstakosUser.
    # The second element of the tuple dictates whether the attribute can be
    # changed by the user or is automatically set by the provider in every
    # login.
    # Identifier is used to get the unique user identifier of the third
    # party provider!
    user_attr_map = {
        # 'user field': ('provider field', 'mutable by user')
        'identifier': ('uuid', False),
        'email': ('email', True),
        'first_name': ('first_name', True),
        'last_name': ('last_name', True),
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_active_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError:
                    continue
        else:
            params.update(self.message_tpls_compiled)

        for key, value in self.urls.iteritems():
            params['%s_url' % key] = value

        if self.user and self.resolve_available_methods:
            available_providers = self.user.get_enabled_auth_providers()
            for p in available_providers:
                p.resolve_available_methods = False
                if p.module == self.module and p.identifier == self.identifier:
                    available_providers.remove(p)

            get_msg = lambda p: p.get_method_prompt_msg
            params['available_methods'] = \
                ','.join(map(get_msg, available_providers))

            get_msg = lambda p: "<a href='%s'>%s</a>" % \
                (p.get_login_url, p.get_method_prompt_msg)

            params['available_methods_links'] = \
                ','.join(map(get_msg, available_providers))

        params.update(extra_params)
        return params

    def get_template(self, tpl):
        tpls = [
            'im/auth/%s_%s.html' % (self.module, tpl),
            getattr(self, '%s_template' % tpl)
        ]
        found = None
        for tpl in tpls:
            try:
                found = template.loader.get_template(tpl)
                return tpl
            except template.TemplateDoesNotExist:
                continue
        if not found:
            raise template.TemplateDoesNotExist
        return tpl

    def get_username(self):
        return self.get_username_msg

    def get_user_providers(self):
        return self.user.auth_providers.filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_active_providers(self):
        return self.user.auth_providers.active().filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_module_providers(self):
        return self.user.auth_providers.filter(module=self.module)

    def get_user_module_active_providers(self):
        return self.user.auth_providers.active().filter(module=self.module)

    def get_existing_providers(self):
        return ""

    def verified_exists(self):
        return self.get_provider_model().objects.verified(
            self.module, identifier=self.identifier)

    def resolve_policy(self, policy, default=None):

        if policy == 'switch' and default and not self.get_add_policy:
            return not self.get_policy('remove')

        if not self.user:
            return default

        if policy == 'remove' and default is True:
            return self.get_user_active_providers().count() > 1

        if policy == 'add' and default is True:
            limit = self.get_policy('limit')
            if limit <= self.get_user_module_active_providers().count():
                return False

            if self.identifier:
                if self.verified_exists():
                    return False

        return default

    def get_user_policies(self):
        from astakos.im.models import AuthProviderPolicyProfile
        return AuthProviderPolicyProfile.objects.for_user(
            self.user, self.module)

    def get_user_attr_map(self):
        """Get the mapping of provider to user attributes."""
        attr_map = self.user_attr_map
        settings_key = "USER_ATTR_MAP"
        settings_default = self.get_setting(settings_key, attr_map)
        attr_map.update(settings_default)
        return attr_map

    def get_provider_forced_attributes(self):
        """List of attributes that are automatically set by the provider."""
        attr_map = self.get_user_attr_map()
        return [
            attr for attr, (provider_attr, mutable) in attr_map.items()
            if not mutable
        ]

    def get_provider_info_attributes(self):
        """List of providers attributes to be stored in Astakos DB.

        Get list of provider's attributes that will be stored in Astakos DB
        in the 'info_data' field.

        """
        return self.get_setting("PROVIDER_ATTRS", [])

    def get_policy(self, policy):
        module_default = self.module_policies.get(policy)
        settings_key = '%s_POLICY' % policy.upper()
        settings_default = self.get_setting(settings_key, module_default)

        if self.user:
            user_policies = self.get_user_policies()
            settings_default = user_policies.get(policy, settings_default)

        return self.resolve_policy(policy, settings_default)

    def get_message(self, msg, **extra_params):
        """
        Retrieve an auth provider message
        """
        if msg.endswith('_msg'):
            msg = msg.replace('_msg', '')
        params = self._message_params(**extra_params)

        # is message ???
        tpl = self.message_tpls_compiled.get(msg.lower(), None)
        if not tpl:
            msg_key = 'AUTH_PROVIDER_%s' % msg.upper()
            try:
                tpl = getattr(astakos_messages, msg_key)
            except AttributeError:
                try:
                    msg_key = msg.upper()
                    tpl = getattr(astakos_messages, msg_key)
                except AttributeError:
                    tpl = ''

        in_settings = self.get_setting(msg)
        if in_settings:
            tpl = in_settings

        return tpl.format(**params)

    @property
    def urls(self):
        urls = {
            'login': reverse(self.login_view),
            'add': reverse(self.login_view),
            'profile': reverse('edit_profile'),
        }
        if self.user:
            urls.update({
                'resend_activation':
                self.user.get_resend_activation_url(),
            })
        if self.identifier and self._instance:
            urls.update({
                'switch':
                reverse(self.login_view) +
                '?switch_from=%d' % self._instance.pk,
                'remove':
                reverse('remove_auth_provider',
                        kwargs={'pk': self._instance.pk})
            })
        urls.update(self.module_urls)
        return urls

    def get_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(),
                                                name.upper())

    def get_global_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDERS_%s' % name.upper()

    def has_global_setting(self, name):
        return hasattr(settings, self.get_global_setting_key(name))

    def has_setting(self, name):
        return hasattr(settings, self.get_setting_key(name))

    def get_setting(self, name, default=None):
        attr = self.get_setting_key(name)
        if not self.has_setting(name):
            return self.get_global_setting(name, default)
        return getattr(settings, attr, default)

    def get_global_setting(self, name, default=None):
        attr = self.get_global_setting_key(name)
        if not self.has_global_setting(name):
            return default
        return getattr(settings, attr, default)

    @property
    def provider_details(self):
        if self._provider_details:
            return self._provider_details

        self._provider_details = {}

        if self._instance:
            self._provider_details = self._instance.__dict__

        if self.user and self.identifier:
            if self.identifier:
                try:
                    self._provider_details = \
                        self.user.get_auth_providers().get(
                            module=self.module,
                            identifier=self.identifier).__dict__
                except Exception:
                    return {}
        return self._provider_details

    def __getattr__(self, key):
        if not key.startswith('get_'):
            return super(AuthProvider, self).__getattribute__(key)

        key = key.replace('get_', '')
        if key.endswith('_msg'):
            return self.get_message(key)

        if key.endswith('_policy'):
            return self.get_policy(key.replace('_policy', ''))

        if key.endswith('_url'):
            key = key.replace('_url', '')
            return self.urls.get(key)

        if key.endswith('_icon'):
            key = key.replace('_msg', '_icon')
            return settings.MEDIA_URL + self.get_message(key)

        if key.endswith('_setting'):
            key = key.replace('_setting', '')
            return self.get_message(key)

        if key.endswith('_template'):
            key = key.replace('_template', '')
            return self.get_template(key)

        return super(AuthProvider, self).__getattribute__(key)

    def is_active(self):
        return self.module_enabled

    @property
    def log_display(self):
        dsp = "%sAuth" % self.module.title()
        if self.user:
            dsp += "[%s]" % self.user.log_display
            if self.identifier:
                dsp += '[%s]' % self.identifier
                if self._instance and self._instance.pk:
                    dsp += '[%d]' % self._instance.pk
        return dsp

    def log(self, msg, *args, **kwargs):
        level = kwargs.pop('level', logging.INFO)
        message = '%s: %s' % (self.log_display, msg)
        logger.log(level, message, *args, **kwargs)
Beispiel #49
0
    n, _ = parse_with_style(s)
    return n


UNITS = {
    'bytes': {
        'DISPLAY': ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'],
        'BASE': 1024,
    }
}

STYLE_TO_EXP = OrderedDict(
    [('b',  0),
     ('kb', 1),
     ('mb', 2),
     ('gb', 3),
     ('tb', 4),
     ('pb', 5),
     ]
)

STYLES = STYLE_TO_EXP.keys() + ['auto', 'none']


class StyleError(Exception):
    pass


def show_float(n):
    if n < 1:
        return "%.3f" % n
Beispiel #50
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using '),
        ('required', '{title} is required. You can assign it '
         'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
         'trying to access {service_name}. '
         'Unfortunately, we are not accepting new '
         'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
         'Please use one of your other available methods '
         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png')))

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'required': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies['automoderate'] = not \
            astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    self.message_tpls_compiled[key] = msg.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else:
Beispiel #51
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("Please provide a user ID or email")

        identifier = args[0]
        if identifier.isdigit():
            users = AstakosUser.objects.filter(id=int(identifier))
        else:
            try:
                uuid.UUID(identifier)
            except:
                users = AstakosUser.objects.filter(email__iexact=identifier)
            else:
                users = AstakosUser.objects.filter(uuid=identifier)
        if users.count() == 0:
            field = "id" if identifier.isdigit() else "email"
            msg = "Unknown user with %s '%s'" % (field, identifier)
            raise CommandError(msg)

        for user in users:
            kv = OrderedDict(
                [
                    ("id", user.id),
                    ("uuid", user.uuid),
                    ("status", user.status_display),
                    ("email", user.email),
                    ("first name", user.first_name),
                    ("last name", user.last_name),
                    ("admin", user.is_superuser),
                    ("last login", user.last_login),
                    ("date joined", user.date_joined),
                    ("last update", user.updated),
                    # ('token', user.auth_token),
                    ("token expiration", user.auth_token_expires),
                    ("providers", user.auth_providers_display),
                    ("groups", [elem.name for elem in user.groups.all()]),
                    ("permissions", [elem.codename for elem in user.user_permissions.all()]),
                    ("group permissions", user.get_group_permissions()),
                    ("email_verified", user.email_verified),
                    ("moderated", user.moderated),
                    ("rejected", user.is_rejected),
                    ("active", user.is_active),
                    ("username", user.username),
                    ("activation_sent_date", user.activation_sent),
                    ("last_login_details", user.last_login_info_display),
                ]
            )

            if get_latest_terms():
                has_signed_terms = user.signed_terms
                kv["has_signed_terms"] = has_signed_terms
                if has_signed_terms:
                    kv["date_signed_terms"] = user.date_signed_terms

            utils.pprint_table(self.stdout, [kv.values()], kv.keys(), options["output_format"], vertical=True)

            if options["list_quotas"] and user.is_accepted():
                unit_style = options["unit_style"]
                check_style(unit_style)

                quotas = get_user_quotas(user)
                if quotas:
                    self.stdout.write("\n")
                    print_data, labels = show_user_quotas(quotas, style=unit_style)
                    utils.pprint_table(self.stdout, print_data, labels, options["output_format"], title="User Quota")

            if options["list_projects"]:
                print_data, labels = ownerships(user)
                if print_data:
                    self.stdout.write("\n")
                    utils.pprint_table(
                        self.stdout, print_data, labels, options["output_format"], title="Owned Projects"
                    )

                print_data, labels = memberships(user)
                if print_data:
                    self.stdout.write("\n")
                    utils.pprint_table(
                        self.stdout, print_data, labels, options["output_format"], title="Project Memberships"
                    )
Beispiel #52
0
class AMQPPukaClient(object):
    """
    AMQP generic client implementing most of the basic AMQP operations.

    """
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=100, logger=None):
        """
        Format hosts as "amqp://*****:*****@host:port"
        max_retries=0 defaults to unlimited retries

        """

        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
        self.unsend = OrderedDict()
        self.consume_promises = []
        self.exchanges = []
        if logger:
            self.log = logger
        else:
            logger = logging.getLogger("amqp")
            logging.basicConfig()
            self.log = logger

    def connect(self, retries=0):
        if self.max_retries and retries >= self.max_retries:
            self.log.error("Aborting after %d retries", retries)
            raise AMQPConnectionError('Aborting after %d connection failures.'
                                      % retries)
            return

        # Pick up a host
        host = self.hosts.pop()
        self.hosts.insert(0, host)

        self.client = Client(host, pubacks=self.confirms)

        host = host.split('@')[-1]
        self.log.debug('Connecting to node %s' % host)

        try:
            promise = self.client.connect()
            self.client.wait(promise)
        except socket_error as e:
            if retries < len(self.hosts):
                self.log.warning('Cannot connect to host %s: %s', host, e)
            else:
                self.log.error('Cannot connect to host %s: %s', host, e)
                sleep(1)
            return self.connect(retries + 1)

        self.log.info('Successfully connected to host: %s', host)

        # Setup TCP keepalive option
        self.client.sd.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        # Keepalive time
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
        # Keepalive interval
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 2)
        # Keepalive retry
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 10)

        self.log.info('Creating channel')

        # Clear consume_promises each time connecting, since they are related
        # to the connection object
        self.consume_promises = []

        if self.unacked:
            self._resend_unacked_messages()

        if self.unsend:
            self._resend_unsend_messages()

        if self.consumers:
            for queue, callback in self.consumers.items():
                self.basic_consume(queue, callback)

        if self.exchanges:
            exchanges = self.exchanges
            self.exchanges = []
            for exchange, type in exchanges:
                self.exchange_declare(exchange, type)

    @reconnect_decorator
    def reconnect(self):
        self.close()
        self.connect()

    def exchange_declare(self, exchange, type='direct'):
        """Declare an exchange
        @type exchange_name: string
        @param exchange_name: name of the exchange
        @type exchange_type: string
        @param exhange_type: one of 'direct', 'topic', 'fanout'

        """
        self.log.info('Declaring %s exchange: %s', type, exchange)
        promise = self.client.exchange_declare(exchange=exchange,
                                               type=type,
                                               durable=True,
                                               auto_delete=False)
        self.client.wait(promise)
        self.exchanges.append((exchange, type))

    @reconnect_decorator
    def queue_declare(self, queue, exclusive=False,
                      mirrored=True, mirrored_nodes='all',
                      dead_letter_exchange=None):
        """Declare a queue

        @type queue: string
        @param queue: name of the queue
        @param mirrored: whether the queue will be mirrored to other brokers
        @param mirrored_nodes: the policy for the mirrored queue.
            Available policies:
                - 'all': The queue is mirrored to all nodes and the
                  master node is the one to which the client is
                  connected
                - a list of nodes. The queue will be mirrored only to
                  the specified nodes, and the master will be the
                  first node in the list. Node names must be provided
                  and not host IP. example: [node1@rabbit,node2@rabbit]

        """
        self.log.info('Declaring queue: %s', queue)

        if mirrored:
            if mirrored_nodes == 'all':
                arguments = {'x-ha-policy': 'all'}
            elif isinstance(mirrored_nodes, list):
                arguments = {'x-ha-policy': 'nodes',
                             'x-ha-policy-params': mirrored_nodes}
            else:
                raise AttributeError
        else:
            arguments = {}

        if dead_letter_exchange:
            arguments['x-dead-letter-exchange'] = dead_letter_exchange

        promise = self.client.queue_declare(queue=queue, durable=True,
                                            exclusive=exclusive,
                                            auto_delete=False,
                                            arguments=arguments)
        self.client.wait(promise)

    def queue_bind(self, queue, exchange, routing_key):
        self.log.debug('Binding queue %s to exchange %s with key %s'
                       % (queue, exchange, routing_key))
        promise = self.client.queue_bind(exchange=exchange, queue=queue,
                                         routing_key=routing_key)
        self.client.wait(promise)

    @reconnect_decorator
    def basic_publish(self, exchange, routing_key, body, headers={}):
        """Publish a message with a specific routing key """
        self._publish(exchange, routing_key, body, headers)

        self.flush_buffer()

        if self.confirms and len(self.unacked) >= self.confirm_buffer:
            self.get_confirms()

    @reconnect_decorator
    def basic_publish_multi(self, exchange, routing_key, bodies):
        for body in bodies:
            self.unsend[body] = (exchange, routing_key)

        for body in bodies:
            self._publish(exchange, routing_key, body)
            self.unsend.pop(body)

        self.flush_buffer()

        if self.confirms:
            self.get_confirms()

    def _publish(self, exchange, routing_key, body, headers={}):
        # Persisent messages by default!
        headers['delivery_mode'] = 2
        promise = self.client.basic_publish(exchange=exchange,
                                            routing_key=routing_key,
                                            body=body, headers=headers)

        if self.confirms:
            self.unacked[promise] = (exchange, routing_key, body)

        return promise

    @reconnect_decorator
    def flush_buffer(self):
        while self.client.needs_write():
            self.client.on_write()

    @reconnect_decorator
    def get_confirms(self):
        for promise in self.unacked.keys():
            self.client.wait(promise)
            self.unacked.pop(promise)

    @reconnect_decorator
    def _resend_unacked_messages(self):
        """Resend unacked messages in case of a connection failure."""
        msgs = self.unacked.values()
        self.unacked.clear()
        for exchange, routing_key, body in msgs:
            self.log.debug('Resending message %s' % body)
            self.basic_publish(exchange, routing_key, body)

    @reconnect_decorator
    def _resend_unsend_messages(self):
        """Resend unsend messages in case of a connection failure."""
        for body in self.unsend.keys():
            (exchange, routing_key) = self.unsend[body]
            self.basic_publish(exchange, routing_key, body)
            self.unsend.pop(body)

    @reconnect_decorator
    def basic_consume(self, queue, callback, prefetch_count=0):
        """Consume from a queue.

        @type queue: string or list of strings
        @param queue: the name or list of names from the queues to consume
        @type callback: function
        @param callback: the callback function to run when a message arrives

        """
        # Store the queues and the callback
        self.consumers[queue] = callback

        def handle_delivery(promise, msg):
            """Hide promises and messages without body"""
            if 'body' in msg:
                callback(self, msg)
            else:
                self.log.debug("Message without body %s" % msg)
                raise socket_error

        consume_promise = \
            self.client.basic_consume(queue=queue,
                                      prefetch_count=prefetch_count,
                                      callback=handle_delivery)

        self.consume_promises.append(consume_promise)
        return consume_promise

    @reconnect_decorator
    def basic_wait(self, promise=None, timeout=0):
        """Wait for messages from the queues declared by basic_consume.

        This function will block until a message arrives from the queues that
        have been declared with basic_consume. If the optional arguments
        'promise' is given, only messages for this promise will be delivered.

        """
        if promise is not None:
            return self.client.wait(promise, timeout)
        else:
            return self.client.wait(self.consume_promises, timeout)

    @reconnect_decorator
    def basic_get(self, queue):
        """Get a single message from a queue.

        This is a non-blocking method for getting messages from a queue.
        It will return None if the queue is empty.

        """
        get_promise = self.client.basic_get(queue=queue)
        result = self.client.wait(get_promise)
        if 'empty' in result:
            # The queue is empty
            return None
        else:
            return result

    @reconnect_decorator
    def basic_ack(self, message):
        self.client.basic_ack(message)

    @reconnect_decorator
    def basic_nack(self, message):
        self.client.basic_ack(message)

    @reconnect_decorator
    def basic_reject(self, message, requeue=False):
        """Reject a message.

        If requeue option is False and a dead letter exchange is associated
        with the queue, the message will be routed to the dead letter exchange.

        """
        self.client.basic_reject(message, requeue=requeue)

    def close(self):
        """Check that messages have been send and close the connection."""
        self.log.debug("Closing connection to %s", self.client.host)
        try:
            if self.confirms:
                self.get_confirms()
            close_promise = self.client.close()
            self.client.wait(close_promise)
        except (socket_error, spec_exceptions.ConnectionForced) as e:
            self.log.error('Connection closed while closing connection:%s', e)

    def queue_delete(self, queue, if_unused=True, if_empty=True):
        """Delete a queue.

        Returns False if the queue does not exist
        """
        try:
            promise = self.client.queue_delete(queue=queue,
                                               if_unused=if_unused,
                                               if_empty=if_empty)
            self.client.wait(promise)
            return True
        except spec_exceptions.NotFound:
            self.log.info("Queue %s does not exist", queue)
            return False

    def exchange_delete(self, exchange, if_unused=True):
        """Delete an exchange."""
        try:

            promise = self.client.exchange_delete(exchange=exchange,
                                                  if_unused=if_unused)
            self.client.wait(promise)
            return True
        except spec_exceptions.NotFound:
            self.log.info("Exchange %s does not exist", exchange)
            return False

    @reconnect_decorator
    def basic_cancel(self, promise=None):
        """Cancel consuming from a queue. """
        if promise is not None:
            self.client.basic_cancel(promise)
        else:
            for promise in self.consume_promises:
                self.client.basic_cancel(promise)
Beispiel #53
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using {account_prompt}'),
        ('required', '{title} is required. You can assign it '
                     'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
                                'trying to access {service_name}. '
                                'Unfortunately, we are not accepting new '
                                'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
                         'Please use one of your other available methods '
                         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png'))
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'mirror_groups': False,  # Currently used only by LDAP
        'required': False,
        'autoverify': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    # Mapping of provider's attributes to attributes of AstakosUser.
    # The second element of the tuple dictates whether the attribute can be
    # changed by the user or is automatically set by the provider in every
    # login.
    # Identifier is used to get the unique user identifier of the third
    # party provider!
    user_attr_map = {
        # 'user field': ('provider field', 'mutable by user')
        'identifier': ('uuid', False),
        'email': ('email', True),
        'first_name': ('first_name', True),
        'last_name': ('last_name', True),
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_active_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy",
                     group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError:
                    continue
        else:
            params.update(self.message_tpls_compiled)

        for key, value in self.urls.iteritems():
            params['%s_url' % key] = value

        if self.user and self.resolve_available_methods:
            available_providers = self.user.get_enabled_auth_providers()
            for p in available_providers:
                p.resolve_available_methods = False
                if p.module == self.module and p.identifier == self.identifier:
                    available_providers.remove(p)

            get_msg = lambda p: p.get_method_prompt_msg
            params['available_methods'] = \
                ','.join(map(get_msg, available_providers))

            get_msg = lambda p: "<a href='%s'>%s</a>" % \
                (p.get_login_url, p.get_method_prompt_msg)

            params['available_methods_links'] = \
                ','.join(map(get_msg, available_providers))

        params.update(extra_params)
        return params

    def get_template(self, tpl):
        tpls = ['im/auth/%s_%s.html' % (self.module, tpl),
                getattr(self, '%s_template' % tpl)]
        found = None
        for tpl in tpls:
            try:
                found = template.loader.get_template(tpl)
                return tpl
            except template.TemplateDoesNotExist:
                continue
        if not found:
            raise template.TemplateDoesNotExist
        return tpl

    def get_username(self):
        return self.get_username_msg

    def get_user_providers(self):
        return self.user.auth_providers.filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_active_providers(self):
        return self.user.auth_providers.active().filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_module_providers(self):
        return self.user.auth_providers.filter(module=self.module)

    def get_user_module_active_providers(self):
        return self.user.auth_providers.active().filter(module=self.module)

    def get_existing_providers(self):
        return ""

    def verified_exists(self):
        return self.get_provider_model().objects.verified(
            self.module, identifier=self.identifier)

    def resolve_policy(self, policy, default=None):

        if policy == 'switch' and default and not self.get_add_policy:
            return not self.get_policy('remove')

        if not self.user:
            return default

        if policy == 'remove' and default is True:
            return self.get_user_active_providers().count() > 1

        if policy == 'add' and default is True:
            limit = self.get_policy('limit')
            if limit <= self.get_user_module_active_providers().count():
                return False

            if self.identifier:
                if self.verified_exists():
                    return False

        return default

    def get_user_policies(self):
        from astakos.im.models import AuthProviderPolicyProfile
        return AuthProviderPolicyProfile.objects.for_user(self.user,
                                                          self.module)

    def get_user_attr_map(self):
        """Get the mapping of provider to user attributes."""
        attr_map = self.user_attr_map
        settings_key = "USER_ATTR_MAP"
        settings_default = self.get_setting(settings_key, attr_map)
        attr_map.update(settings_default)
        return attr_map

    def get_provider_forced_attributes(self):
        """List of attributes that are automatically set by the provider."""
        attr_map = self.get_user_attr_map()
        return [attr
                for attr, (provider_attr, mutable) in attr_map.items()
                if not mutable]

    def get_provider_info_attributes(self):
        """List of providers attributes to be stored in Astakos DB.

        Get list of provider's attributes that will be stored in Astakos DB
        in the 'info_data' field.

        """
        return self.get_setting("PROVIDER_ATTRS", [])


    def get_policy(self, policy):
        module_default = self.module_policies.get(policy)
        settings_key = '%s_POLICY' % policy.upper()
        settings_default = self.get_setting(settings_key, module_default)

        if self.user:
            user_policies = self.get_user_policies()
            settings_default = user_policies.get(policy, settings_default)

        return self.resolve_policy(policy, settings_default)

    def get_message(self, msg, **extra_params):
        """
        Retrieve an auth provider message
        """
        if msg.endswith('_msg'):
            msg = msg.replace('_msg', '')
        params = self._message_params(**extra_params)

        # is message ???
        tpl = self.message_tpls_compiled.get(msg.lower(), None)
        if not tpl:
            msg_key = 'AUTH_PROVIDER_%s' % msg.upper()
            try:
                tpl = getattr(astakos_messages, msg_key)
            except AttributeError:
                try:
                    msg_key = msg.upper()
                    tpl = getattr(astakos_messages, msg_key)
                except AttributeError:
                    tpl = ''

        in_settings = self.get_setting(msg)
        if in_settings:
            tpl = in_settings

        return tpl.format(**params)

    @property
    def urls(self):
        urls = {
            'login': reverse(self.login_view),
            'add': reverse(self.login_view),
            'profile': reverse('edit_profile'),
        }
        if self.user:
            urls.update({
                'resend_activation': self.user.get_resend_activation_url(),
            })
        if self.identifier and self._instance:
            urls.update({
                'switch': reverse(self.login_view) + '?switch_from=%d' %
                self._instance.pk,
                'remove': reverse('remove_auth_provider',
                                  kwargs={'pk': self._instance.pk})
            })
        urls.update(self.module_urls)
        return urls

    def get_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(),
                                                name.upper())

    def get_global_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDERS_%s' % name.upper()

    def has_global_setting(self, name):
        return hasattr(settings, self.get_global_setting_key(name))

    def has_setting(self, name):
        return hasattr(settings, self.get_setting_key(name))

    def get_setting(self, name, default=None):
        attr = self.get_setting_key(name)
        if not self.has_setting(name):
            return self.get_global_setting(name, default)
        return getattr(settings, attr, default)

    def get_global_setting(self, name, default=None):
        attr = self.get_global_setting_key(name)
        if not self.has_global_setting(name):
            return default
        return getattr(settings, attr, default)

    @property
    def provider_details(self):
        if self._provider_details:
            return self._provider_details

        self._provider_details = {}

        if self._instance:
            self._provider_details = self._instance.__dict__

        if self.user and self.identifier:
            if self.identifier:
                try:
                    self._provider_details = \
                        self.user.get_auth_providers().get(
                            module=self.module,
                            identifier=self.identifier).__dict__
                except Exception:
                    return {}
        return self._provider_details

    def __getattr__(self, key):
        if not key.startswith('get_'):
            return super(AuthProvider, self).__getattribute__(key)

        key = key.replace('get_', '')
        if key.endswith('_msg'):
            return self.get_message(key)

        if key.endswith('_policy'):
            return self.get_policy(key.replace('_policy', ''))

        if key.endswith('_url'):
            key = key.replace('_url', '')
            return self.urls.get(key)

        if key.endswith('_icon'):
            key = key.replace('_msg', '_icon')
            return settings.MEDIA_URL + self.get_message(key)

        if key.endswith('_setting'):
            key = key.replace('_setting', '')
            return self.get_message(key)

        if key.endswith('_template'):
            key = key.replace('_template', '')
            return self.get_template(key)

        return super(AuthProvider, self).__getattribute__(key)

    def is_active(self):
        return self.module_enabled

    @property
    def log_display(self):
        dsp = "%sAuth" % self.module.title()
        if self.user:
            dsp += "[%s]" % self.user.log_display
            if self.identifier:
                dsp += '[%s]' % self.identifier
                if self._instance and self._instance.pk:
                    dsp += '[%d]' % self._instance.pk
        return dsp

    def log(self, msg, *args, **kwargs):
        level = kwargs.pop('level', logging.INFO)
        message = '%s: %s' % (self.log_display, msg)
        logger.log(level, message, *args, **kwargs)
Beispiel #54
0
class AMQPPukaClient(object):
    """
    AMQP generic client implementing most of the basic AMQP operations.

    """
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=100, logger=None):
        """
        Format hosts as "amqp://*****:*****@host:port"
        max_retries=0 defaults to unlimited retries

        """

        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()
        self.unsend = OrderedDict()
        self.consume_promises = []
        self.exchanges = []
        if logger:
            self.log = logger
        else:
            logger = logging.getLogger("amqp")
            logging.basicConfig()
            self.log = logger

    def connect(self, retries=0):
        if self.max_retries and retries >= self.max_retries:
            self.log.error("Aborting after %d retries", retries)
            raise AMQPConnectionError('Aborting after %d connection failures.'
                                      % retries)
            return

        # Pick up a host
        host = self.hosts.pop()
        self.hosts.insert(0, host)

        self.client = Client(host, pubacks=self.confirms)

        host = host.split('@')[-1]
        self.log.debug('Connecting to node %s' % host)

        try:
            promise = self.client.connect()
            self.client.wait(promise)
        except socket_error as e:
            if retries < len(self.hosts):
                self.log.warning('Cannot connect to host %s: %s', host, e)
            else:
                self.log.error('Cannot connect to host %s: %s', host, e)
                sleep(1)
            return self.connect(retries + 1)

        self.log.info('Successfully connected to host: %s', host)

        # Setup TCP keepalive option
        self.client.sd.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        # Keepalive time
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
        # Keepalive interval
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 2)
        # Keepalive retry
        self.client.sd.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 10)

        self.log.info('Creating channel')

        # Clear consume_promises each time connecting, since they are related
        # to the connection object
        self.consume_promises = []

        if self.unacked:
            self.log.debug("Resending unacked messages from previous"
                           " connection")
            self._resend_unacked_messages()

        if self.unsend:
            self.log.debug("Resending unsent messages from previous"
                           " connection")
            self._resend_unsend_messages()

        if self.exchanges:
            exchanges = self.exchanges
            self.exchanges = []
            for exchange, type in exchanges:
                self.exchange_declare(exchange, type)

        if self.consumers:
            for queue, callback in self.consumers.items():
                self.basic_consume(queue, callback)

    @reconnect_decorator
    def reconnect(self, timeout=None):
        try:
            self.close(timeout=timeout)
        except:
            self.log.exception("Ignoring unhandled exception while closing"
                               " old connection.")
        self.connect()

    def exchange_declare(self, exchange, type='direct'):
        """Declare an exchange
        @type exchange_name: string
        @param exchange_name: name of the exchange
        @type exchange_type: string
        @param exhange_type: one of 'direct', 'topic', 'fanout'

        """
        self.log.info('Declaring %s exchange: %s', type, exchange)
        promise = self.client.exchange_declare(exchange=exchange,
                                               type=type,
                                               durable=True,
                                               auto_delete=False)
        self.client.wait(promise)
        self.exchanges.append((exchange, type))

    @reconnect_decorator
    def queue_declare(self, queue, exclusive=False,
                      mirrored=True, mirrored_nodes='all',
                      dead_letter_exchange=None, ttl=None):
        """Declare a queue

        @type queue: string
        @param queue: name of the queue
        @param mirrored: whether the queue will be mirrored to other brokers
        @param mirrored_nodes: the policy for the mirrored queue.
            Available policies:
                - 'all': The queue is mirrored to all nodes and the
                  master node is the one to which the client is
                  connected
                - a list of nodes. The queue will be mirrored only to
                  the specified nodes, and the master will be the
                  first node in the list. Node names must be provided
                  and not host IP. example: [node1@rabbit,node2@rabbit]
        @type ttl: int
        @param ttl: Queue TTL in seconds

        """
        self.log.info('Declaring queue: %s', queue)

        if mirrored:
            if mirrored_nodes == 'all':
                arguments = {'x-ha-policy': 'all'}
            elif isinstance(mirrored_nodes, list):
                arguments = {'x-ha-policy': 'nodes',
                             'x-ha-policy-params': mirrored_nodes}
            else:
                raise AttributeError
        else:
            arguments = {}

        if ttl is not None:
            arguments['x-expires'] = ttl * 1000

        if dead_letter_exchange:
            arguments['x-dead-letter-exchange'] = dead_letter_exchange

        promise = self.client.queue_declare(queue=queue, durable=True,
                                            exclusive=exclusive,
                                            auto_delete=False,
                                            arguments=arguments)
        self.client.wait(promise)

    def queue_bind(self, queue, exchange, routing_key):
        self.log.debug('Binding queue %s to exchange %s with key %s'
                       % (queue, exchange, routing_key))
        promise = self.client.queue_bind(exchange=exchange, queue=queue,
                                         routing_key=routing_key)
        self.client.wait(promise)

    @reconnect_decorator
    def basic_publish(self, exchange, routing_key, body, headers={}):
        """Publish a message with a specific routing key """
        self._publish(exchange, routing_key, body, headers)

        self.flush_buffer()

        if self.confirms and len(self.unacked) >= self.confirm_buffer:
            self.get_confirms()

    @reconnect_decorator
    def basic_publish_multi(self, exchange, routing_key, bodies):
        for body in bodies:
            self.unsend[body] = (exchange, routing_key)

        for body in bodies:
            self._publish(exchange, routing_key, body)
            self.unsend.pop(body)

        self.flush_buffer()

        if self.confirms:
            self.get_confirms()

    def _publish(self, exchange, routing_key, body, headers={}):
        # Persisent messages by default!
        headers['delivery_mode'] = 2

        if self.confirms:
            callback = self.handle_publisher_confirm
        else:
            callback = None

        promise = self.client.basic_publish(exchange=exchange,
                                            routing_key=routing_key,
                                            body=body, headers=headers,
                                            callback=callback)

        if self.confirms:
            self.unacked[promise] = (exchange, routing_key, body)

        return promise

    def handle_publisher_confirm(self, promise, result):
        """Handle publisher confirmation message.

        Callback function which handles publisher confirmation by removing
        the promise (and message) from 'unacked' messages.

        """
        msg = self.unacked.pop(promise, None)
        if msg is None:
            self.log.warning("Received publisher confirmation for"
                             " unknown promise '%s'", promise)

    @reconnect_decorator
    def flush_buffer(self):
        while self.client.needs_write():
            self.client.on_write()

    @reconnect_decorator
    def get_confirms(self):
        """Wait for all publisher confirmations."""
        while self.unacked:
            self.client.wait(self.unacked.keys())

    @reconnect_decorator
    def _resend_unacked_messages(self):
        """Resend unacked messages in case of a connection failure."""
        msgs = self.unacked.values()
        self.unacked.clear()
        for exchange, routing_key, body in msgs:
            self.log.debug('Resending message %s' % body)
            self.basic_publish(exchange, routing_key, body)

    @reconnect_decorator
    def _resend_unsend_messages(self):
        """Resend unsend messages in case of a connection failure."""
        for body in self.unsend.keys():
            (exchange, routing_key) = self.unsend[body]
            self.basic_publish(exchange, routing_key, body)
            self.unsend.pop(body)

    @reconnect_decorator
    def basic_consume(self, queue, callback, no_ack=False, prefetch_count=0):
        """Consume from a queue.

        @type queue: string or list of strings
        @param queue: the name or list of names from the queues to consume
        @type callback: function
        @param callback: the callback function to run when a message arrives

        """
        self.log.debug("Consume from queue '%s'", queue)
        # Store the queues and the callback
        self.consumers[queue] = callback

        def handle_delivery(promise, msg):
            """Hide promises and messages without body"""
            if 'body' in msg:
                callback(self, msg)
            else:
                self.log.debug("Message without body %s" % msg)
                raise socket_error

        consume_promise = \
            self.client.basic_consume(queue=queue,
                                      prefetch_count=prefetch_count,
                                      callback=handle_delivery,
                                      no_ack=no_ack)

        self.consume_promises.append(consume_promise)
        return consume_promise

    @reconnect_decorator
    def basic_wait(self, promise=None, timeout=0):
        """Wait for messages from the queues declared by basic_consume.

        This function will block until a message arrives from the queues that
        have been declared with basic_consume. If the optional arguments
        'promise' is given, only messages for this promise will be delivered.

        """
        if promise is not None:
            return self.client.loop(timeout)
        else:
            return self.client.wait(self.consume_promises, timeout)

    @reconnect_decorator
    def basic_get(self, queue, no_ack=False):
        """Get a single message from a queue.

        This is a non-blocking method for getting messages from a queue.
        It will return None if the queue is empty.

        """
        get_promise = self.client.basic_get(queue=queue, no_ack=no_ack)
        result = self.client.wait(get_promise)
        if 'empty' in result:
            # The queue is empty
            return None
        else:
            return result

    @reconnect_decorator
    def basic_ack(self, message):
        self.client.basic_ack(message)

    @reconnect_decorator
    def basic_nack(self, message):
        self.client.basic_ack(message)

    @reconnect_decorator
    def basic_reject(self, message, requeue=False):
        """Reject a message.

        If requeue option is False and a dead letter exchange is associated
        with the queue, the message will be routed to the dead letter exchange.

        """
        self.client.basic_reject(message, requeue=requeue)

    def close(self, timeout=None):
        """Check that messages have been send and close the connection."""
        self.log.info("Closing connection to %s", self.client.host)
        try:
            # Flush buffer before closing connection
            self.flush_buffer()
            # Try to get confirmations
            if self.confirms and self.unacked:
                self.log.debug("Getting pending publisher confirmations..")
                self.get_confirms()
            # And close the connection
            close_promise = self.client.close()
            self.log.debug("Waiting for connection to close..")
            self.client.wait(close_promise, timeout=timeout)
        except (socket_error, spec_exceptions.ConnectionForced) as e:
            self.log.error('Connection closed while closing connection:%s', e)

    def queue_delete(self, queue, if_unused=True, if_empty=True):
        """Delete a queue.

        Returns False if the queue does not exist
        """
        try:
            promise = self.client.queue_delete(queue=queue,
                                               if_unused=if_unused,
                                               if_empty=if_empty)
            self.client.wait(promise)
            return True
        except spec_exceptions.NotFound:
            self.log.info("Queue %s does not exist", queue)
            return False

    def exchange_delete(self, exchange, if_unused=True):
        """Delete an exchange."""
        try:

            promise = self.client.exchange_delete(exchange=exchange,
                                                  if_unused=if_unused)
            self.client.wait(promise)
            return True
        except spec_exceptions.NotFound:
            self.log.info("Exchange %s does not exist", exchange)
            return False

    @reconnect_decorator
    def basic_cancel(self, promise=None, timeout=None):
        """Cancel consuming from a queue. """
        if promise is not None:
            promises = [self.client.basic_cancel(promise)]
        else:
            promises = [self.client.basic_cancel(p)
                        for p in self.consume_promises]
        self.client.wait(promises, timeout=timeout)
Beispiel #55
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using '),
        ('required', '{title} is required. You can assign it '
                     'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
                                'trying to access {service_name}. '
                                'Unfortunately, we are not accepting new '
                                'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
                         'Please use one of your other available methods '
                         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png'))
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'required': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies['automoderate'] = not \
            astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy",
                     group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else:
Beispiel #56
0
class AMQPHaighaClient():
    def __init__(self, hosts=settings.AMQP_HOSTS, max_retries=30,
                 confirms=True, confirm_buffer=200):
        self.hosts = hosts
        shuffle(self.hosts)

        self.max_retries = max_retries
        self.confirms = confirms
        self.confirm_buffer = confirm_buffer

        self.connection = None
        self.channel = None
        self.consumers = {}
        self.unacked = OrderedDict()

    def connect(self):
        """Initialize a connection with the AMQP server. If it fails, retry at
        most <max_retries> times.
        """

        # Patch gevent
        monkey.patch_all()

        retries = 0
        self.connection = None

        # Try to connect at most <max_retries> times
        while self.max_retries == 0 or retries < self.max_retries:
            retries += 1
            # Pick up a host
            host = self.hosts.pop()
            self.hosts.insert(0, host)
            try:
                self.connection = RabbitConnection(logger=logger, debug=True,
                                                   user='******',
                                                   password='******',
                                                   vhost='/', host=host,
                                                   heartbeat=None,
                                                   sock_opts=sock_opts,
                                                   transport='gevent')
                break
            except socket.error as e:
                self.connection = None
                logger.error('Cannot connect to host %s: %s', host, e)
                if retries > 2 * len(self.hosts):
                    sleep(1)

        if not self.connection:
            raise AMQPConnectionError('Aborting after %d connection failures!'
                                      % self.max_retries)

        logger.info('Successfully connected to host: %s', host)

        logger.info('Creating channel')
        self.channel = self.connection.channel()

        if self.confirms:
            self._confirm_select()

        if self.unacked:
            self._resend_unacked_messages()

        if self.consumers:
            for queue, callback in self.consumers.items():
                self.basic_consume(queue, callback)

    def exchange_declare(self, exchange, type='direct'):
        """Declare an exchange
        @type exchange_name: string
        @param exchange_name: name of the exchange
        @type exchange_type: string
        @param exhange_type: one of 'direct', 'topic', 'fanout'

        """

        logger.info('Declaring %s exchange: %s', type, exchange)
        self.channel.exchange.declare(exchange, type,
                                      auto_delete=False, durable=True)

    def queue_declare(self, queue, exclusive=False, mirrored=True,
                      mirrored_nodes='all', ttl=None):
        """Declare a queue

        @type queue: string
        @param queue: name of the queue
        @param mirrored: whether the queue will be mirrored to other brokers
        @param mirrored_nodes: the policy for the mirrored queue.
            Available policies:
                - 'all': The queue is mirrored to all nodes and the
                  master node is the one to which the client is
                  connected
                - a list of nodes. The queue will be mirrored only to
                  the specified nodes, and the master will be the
                  first node in the list. Node names must be provided
                  and not host IP. example: [node1@rabbit,node2@rabbit]
        @type ttl: int
        @param tll: Queue TTL in seconds

        """

        logger.info('Declaring queue: %s', queue)
        if mirrored:
            if mirrored_nodes == 'all':
                arguments = {'x-ha-policy': 'all'}
            elif isinstance(mirrored_nodes, list):
                arguments = {'x-ha-policy': 'nodes',
                             'x-ha-policy-params': mirrored_nodes}
            else:
                raise AttributeError
        else:
            arguments = {}

        if ttl is not None:
            arguments['x-expires'] = ttl * 1000

        self.channel.queue.declare(queue, durable=True, exclusive=exclusive,
                                   auto_delete=False, arguments=arguments)

    def queue_bind(self, queue, exchange, routing_key):
        logger.info('Binding queue %s to exchange %s with key %s', queue,
                    exchange, routing_key)
        self.channel.queue.bind(queue=queue, exchange=exchange,
                                routing_key=routing_key)

    def _confirm_select(self):
        logger.info('Setting channel to confirm mode')
        self.channel.confirm.select()
        self.channel.basic.set_ack_listener(self._ack_received)
        self.channel.basic.set_nack_listener(self._nack_received)

    @reconnect_decorator
    def basic_publish(self, exchange, routing_key, body):
        msg = Message(body, delivery_mode=2)
        mid = self.channel.basic.publish(msg, exchange, routing_key)
        if self.confirms:
            self.unacked[mid] = (exchange, routing_key, body)
            if len(self.unacked) > self.confirm_buffer:
                self.get_confirms()

        logger.debug('Published message %s with id %s', body, mid)

    @reconnect_decorator
    def get_confirms(self):
        self.connection.read_frames()

    @reconnect_decorator
    def _resend_unacked_messages(self):
        msgs = self.unacked.values()
        self.unacked.clear()
        for exchange, routing_key, body in msgs:
            logger.debug('Resending message %s', body)
            self.basic_publish(exchange, routing_key, body)

    @reconnect_decorator
    def _ack_received(self, mid):
        print mid
        logger.debug('Received ACK for message with id %s', mid)
        self.unacked.pop(mid)

    @reconnect_decorator
    def _nack_received(self, mid):
        logger.error('Received NACK for message with id %s. Retrying.', mid)
        (exchange, routing_key, body) = self.unacked[mid]
        self.basic_publish(exchange, routing_key, body)

    def basic_consume(self, queue, callback, no_ack=False, exclusive=False):
        """Consume from a queue.

        @type queue: string or list of strings
        @param queue: the name or list of names from the queues to consume
        @type callback: function
        @param callback: the callback function to run when a message arrives

        """

        self.consumers[queue] = callback
        self.channel.basic.consume(queue, consumer=callback, no_ack=no_ack,
                                   exclusive=exclusive)

    @reconnect_decorator
    def basic_wait(self):
        """Wait for messages from the queues declared by basic_consume.

        This function will block until a message arrives from the queues that
        have been declared with basic_consume. If the optional arguments
        'promise' is given, only messages for this promise will be delivered.

        """

        self.connection.read_frames()
        gevent.sleep(0)

    @reconnect_decorator
    def basic_get(self, queue, no_ack=False):
        self.channel.basic.get(queue, no_ack=no_ack)

    @reconnect_decorator
    def basic_ack(self, message):
        delivery_tag = message.delivery_info['delivery_tag']
        self.channel.basic.ack(delivery_tag)

    @reconnect_decorator
    def basic_nack(self, message):
        delivery_tag = message.delivery_info['delivery_tag']
        self.channel.basic.ack(delivery_tag)

    def close(self):
        try:
            if self.confirms:
                while self.unacked:
                    print self.unacked
                    self.get_confirms()
            self.channel.close()
            close_info = self.channel.close_info
            logger.info('Successfully closed channel. Info: %s', close_info)
            self.connection.close()
        except socket.error as e:
            logger.error('Connection closed while closing connection:%s', e)

    def queue_delete(self, queue, if_unused=True, if_empty=True):
        self.channel.queue.delete(queue, if_unused, if_empty)

    def exchange_delete(self, exchange, if_unused=True):
        self.channel.exchange.delete(exchange, if_unused)

    def basic_class(self):
        pass
Beispiel #57
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict(
        (
            ("title", "{module_title}"),
            ("login_title", "{title} LOGIN"),
            ("method_prompt", "{title} login"),
            ("account_prompt", "{title} account"),
            ("signup_title", "{title}"),
            ("profile_title", "{title}"),
            ("method_details", "{account_prompt}: {identifier}"),
            ("primary_login_prompt", "Login using "),
            ("required", "{title} is required. You can assign it " "from your profile page"),
            ("login_prompt", ""),
            ("add_prompt", "Allows you to login using {title}"),
            ("login_extra", ""),
            ("username", "{username}"),
            (
                "disabled_for_create",
                "It seems this is the first time you're "
                "trying to access {service_name}. "
                "Unfortunately, we are not accepting new "
                "users at this point.",
            ),
            ("switch_success", "Account changed successfully."),
            (
                "cannot_login",
                "{title} is not available for login. "
                "Please use one of your other available methods "
                "to login ({available_methods_links}",
            ),
            # icons should end with _icon
            ("module_medium_icon", "im/auth/icons-medium/{module}.png"),
            ("module_icon", "im/auth/icons/{module}.png"),
        )
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = "im/auth/generic_primary_login.html"
    login_template = "im/auth/generic_login.html"
    signup_template = "im/signup.html"
    login_prompt_template = "im/auth/generic_login_prompt.html"
    signup_prompt_template = "im/auth/signup_prompt.html"

    default_policies = {
        "login": True,
        "create": True,
        "add": True,
        "remove": True,
        "limit": 1,
        "switch": True,
        "add_groups": [],
        "creation_groups": [],
        "required": False,
        "automoderate": not astakos_settings.MODERATION_ENABLED,
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, "pk") and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if "instance" in provider_params:
            self._instance = provider_params["instance"]
            del provider_params["instance"]

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies["automoderate"] = not astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider

        return AuthProvider

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log("removed from group due to add_groups_policy %s", group.name)

        self._instance.delete()
        self.log("removed")

    def add_to_user(self, **params):
        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy", group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)", user.log_display)
                user.delete()

        create_params = {
            "module": self.module,
            "info_data": json.dumps(self.provider_details.get("info", {})),
            "active": True,
            "identifier": self.identifier,
        }
        if "info" in self.provider_details:
            del self.provider_details["info"]

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += " (user: %r)" % self.user
        if self.identifier:
            r += "(identifier: %r)" % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {"module": self.module, "module_title": self.module.title()}
        if self.identifier:
            params["identifier"] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if "info" in self.provider_details:
                if isinstance(self.provider_details["info"], basestring):
                    self.provider_details["info"] = json.loads(self.provider_details["info"])
                for key, val in self.provider_details["info"].iteritems():
                    params["provider_info_%s" % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params["username"] = params[self.username_key]
        else:
            params["username"] = self.identifier

        branding_params = dict(map(lambda k: (k[0].lower(), k[1]), branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    self.message_tpls_compiled[key] = msg.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else: