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 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)
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)
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")
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
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)
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")
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)
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)
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)
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)
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 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)
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 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)
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 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)
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
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')
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)
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)
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)
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)
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')
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)
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)
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)
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)
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')
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)
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)
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)
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')
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
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
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
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
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
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
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:
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)
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
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:
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" )
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)
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)
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)
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:
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
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: