mirror of
https://github.com/ansible/awx.git
synced 2026-05-19 14:57:39 -02:30
Start of group support.
This commit is contained in:
@@ -142,7 +142,7 @@ class PrimordialModel(models.Model):
|
|||||||
active = models.BooleanField(default=True)
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.name)
|
return unicode("%s-%s"% (self.name, self.id))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_user_administrate(cls, user, obj):
|
def can_user_administrate(cls, user, obj):
|
||||||
@@ -284,6 +284,7 @@ class Inventory(CommonModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
verbose_name_plural = _('inventories')
|
verbose_name_plural = _('inventories')
|
||||||
|
unique_together = (("name", "organization"),)
|
||||||
|
|
||||||
organization = models.ForeignKey(Organization, null=False, related_name='inventories')
|
organization = models.ForeignKey(Organization, null=False, related_name='inventories')
|
||||||
|
|
||||||
@@ -291,12 +292,6 @@ class Inventory(CommonModel):
|
|||||||
import lib.urls
|
import lib.urls
|
||||||
return reverse(lib.urls.views_InventoryDetail, args=(self.pk,))
|
return reverse(lib.urls.views_InventoryDetail, args=(self.pk,))
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
if self.organization:
|
|
||||||
return u'%s (%s)' % (self.name, self.organization)
|
|
||||||
else:
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _has_permission_types(cls, user, obj, allowed):
|
def _has_permission_types(cls, user, obj, allowed):
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
@@ -370,6 +365,7 @@ class Host(CommonModelNameNotUnique):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
|
unique_together = (("name", "inventory"),)
|
||||||
|
|
||||||
inventory = models.ForeignKey('Inventory', null=False, related_name='hosts')
|
inventory = models.ForeignKey('Inventory', null=False, related_name='hosts')
|
||||||
|
|
||||||
@@ -395,6 +391,7 @@ class Group(CommonModelNameNotUnique):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
|
unique_together = (("name", "inventory"),)
|
||||||
|
|
||||||
inventory = models.ForeignKey('Inventory', null=False, related_name='groups')
|
inventory = models.ForeignKey('Inventory', null=False, related_name='groups')
|
||||||
parents = models.ManyToManyField('self', symmetrical=False, related_name='children', blank=True)
|
parents = models.ManyToManyField('self', symmetrical=False, related_name='children', blank=True)
|
||||||
@@ -410,10 +407,14 @@ class Group(CommonModelNameNotUnique):
|
|||||||
inventory = Inventory.objects.get(pk=data['inventory'])
|
inventory = Inventory.objects.get(pk=data['inventory'])
|
||||||
return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
|
return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
import lib.urls
|
||||||
|
return reverse(lib.urls.views_GroupsDetail, args=(self.pk,))
|
||||||
|
|
||||||
# FIXME: audit nullables
|
# FIXME: audit nullables
|
||||||
# FIXME: audit cascades
|
# FIXME: audit cascades
|
||||||
|
|
||||||
class VariableData(CommonModel):
|
class VariableData(CommonModelNameNotUnique):
|
||||||
'''
|
'''
|
||||||
A set of host or group variables
|
A set of host or group variables
|
||||||
'''
|
'''
|
||||||
@@ -421,6 +422,7 @@ class VariableData(CommonModel):
|
|||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
verbose_name_plural = _('variable data')
|
verbose_name_plural = _('variable data')
|
||||||
|
unique_together = (("host", "group"),)
|
||||||
|
|
||||||
host = models.ForeignKey('Host', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='variable_data')
|
host = models.ForeignKey('Host', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='variable_data')
|
||||||
group = models.ForeignKey('Group', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='variable_data')
|
group = models.ForeignKey('Group', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='variable_data')
|
||||||
@@ -527,7 +529,15 @@ class Permission(CommonModelNameNotUnique):
|
|||||||
|
|
||||||
permission_type = models.CharField(max_length=64, choices=PERMISSION_TYPE_CHOICES)
|
permission_type = models.CharField(max_length=64, choices=PERMISSION_TYPE_CHOICES)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode("Permission(name=%s,ON(user=%s,team=%s),FOR(project=%s,inventory=%s,type=%s))" % (
|
||||||
|
self.name,
|
||||||
|
self.user,
|
||||||
|
self.team,
|
||||||
|
self.project,
|
||||||
|
self.inventory,
|
||||||
|
self.permission_type
|
||||||
|
))
|
||||||
|
|
||||||
# TODO: other job types (later)
|
# TODO: other job types (later)
|
||||||
|
|
||||||
|
|||||||
@@ -129,13 +129,12 @@ class InventoryTest(BaseTest):
|
|||||||
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
new_host_b = dict(name='asdf1.example.com', inventory=inv.pk)
|
||||||
new_host_c = dict(name='asdf2.example.com', inventory=inv.pk)
|
new_host_c = dict(name='asdf2.example.com', inventory=inv.pk)
|
||||||
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
new_host_d = dict(name='asdf3.example.com', inventory=inv.pk)
|
||||||
# FIXME: should raise 400 not 201, look into required fields in rest_framework
|
new_host_e = dict(name='asdf4.example.com', inventory=inv.pk)
|
||||||
print hosts
|
|
||||||
data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
data0 = self.post(hosts, data=invalid, expect=400, auth=self.get_super_credentials())
|
||||||
data0 = self.post(hosts, data=new_host_a, expect=201, auth=self.get_super_credentials())
|
data0 = self.post(hosts, data=new_host_a, expect=201, auth=self.get_super_credentials())
|
||||||
|
|
||||||
# an org admin can add hosts
|
# an org admin can add hosts
|
||||||
data1 = self.post(hosts, data=new_host_a, expect=201, auth=self.get_normal_credentials())
|
data1 = self.post(hosts, data=new_host_e, expect=201, auth=self.get_normal_credentials())
|
||||||
|
|
||||||
# a normal user cannot add hosts
|
# a normal user cannot add hosts
|
||||||
data2 = self.post(hosts, data=new_host_b, expect=403, auth=self.get_nobody_credentials())
|
data2 = self.post(hosts, data=new_host_b, expect=403, auth=self.get_nobody_credentials())
|
||||||
@@ -143,24 +142,46 @@ class InventoryTest(BaseTest):
|
|||||||
# a normal user with inventory edit permissions (on any inventory) can create hosts
|
# a normal user with inventory edit permissions (on any inventory) can create hosts
|
||||||
edit_perm = Permission.objects.create(
|
edit_perm = Permission.objects.create(
|
||||||
user = self.other_django_user,
|
user = self.other_django_user,
|
||||||
inventory = Inventory.objects.get(pk=1),
|
inventory = Inventory.objects.get(pk=inv.pk),
|
||||||
permission_type = PERM_INVENTORY_WRITE
|
permission_type = PERM_INVENTORY_WRITE
|
||||||
)
|
)
|
||||||
data3 = self.post(hosts, data=new_host_c, expect=201, auth=self.get_other_credentials())
|
data3 = self.post(hosts, data=new_host_c, expect=201, auth=self.get_other_credentials())
|
||||||
|
|
||||||
# hostnames must be unique -- posting a duplicate just returns the previous
|
# hostnames must be unique inside an organization
|
||||||
data4 = self.post(hosts, data=new_host_c, expect=200, auth=self.get_other_credentials())
|
data4 = self.post(hosts, data=new_host_c, expect=400, auth=self.get_other_credentials())
|
||||||
self.assertEqual(data1['id'], data4['id'])
|
|
||||||
|
|
||||||
# a super user can add groups
|
###########################################
|
||||||
|
# GROUPS
|
||||||
|
|
||||||
# an org admin can create groups
|
invalid = dict(name='web1')
|
||||||
|
new_group_a = dict(name='web2', inventory=inv.pk)
|
||||||
|
new_group_b = dict(name='web3', inventory=inv.pk)
|
||||||
|
new_group_c = dict(name='web4', inventory=inv.pk)
|
||||||
|
new_group_d = dict(name='web5', inventory=inv.pk)
|
||||||
|
new_group_e = dict(name='web6', inventory=inv.pk)
|
||||||
|
data0 = self.post(groups, data=invalid, expect=400, auth=self.get_super_credentials())
|
||||||
|
data0 = self.post(groups, data=new_group_a, expect=201, auth=self.get_super_credentials())
|
||||||
|
|
||||||
# a normal user cannot create groups
|
# an org admin can add hosts
|
||||||
|
data1 = self.post(groups, data=new_group_e, expect=201, auth=self.get_normal_credentials())
|
||||||
|
|
||||||
# a normal user with inventory edit permissions can create groups
|
# a normal user cannot add hosts
|
||||||
|
data2 = self.post(groups, data=new_group_b, expect=403, auth=self.get_nobody_credentials())
|
||||||
|
|
||||||
# group names must be unique for each inventory record
|
# a normal user with inventory edit permissions (on any inventory) can create hosts
|
||||||
|
# already done!
|
||||||
|
#edit_perm = Permission.objects.create(
|
||||||
|
# user = self.other_django_user,
|
||||||
|
# inventory = Inventory.objects.get(pk=inv.pk),
|
||||||
|
# permission_type = PERM_INVENTORY_WRITE
|
||||||
|
#)
|
||||||
|
data3 = self.post(groups, data=new_group_c, expect=201, auth=self.get_other_credentials())
|
||||||
|
|
||||||
|
# hostnames must be unique inside an organization
|
||||||
|
data4 = self.post(groups, data=new_group_c, expect=400, auth=self.get_other_credentials())
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# HOSTS->inventories
|
||||||
|
|
||||||
# a super user can associate hosts with inventories
|
# a super user can associate hosts with inventories
|
||||||
|
|
||||||
@@ -170,13 +191,19 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a normal user with edit permission on the inventory can associate hosts with inventories
|
# a normal user with edit permission on the inventory can associate hosts with inventories
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# GROUPS->inventories
|
||||||
|
|
||||||
# a super user can associate groups with inventories
|
# a super user can associate groups with inventories
|
||||||
|
|
||||||
# an org admin can associate groups with inventories
|
# an org admin can associate groups with inventories
|
||||||
|
|
||||||
# a normal user cannot associate hosts with inventories
|
# a normal user cannot associate groups with inventories
|
||||||
|
|
||||||
# a normal user with edit permissions on the inventory can associate hosts with inventories
|
# a normal user with edit permissions on the inventory can associate groups with inventories
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# VARIABLES
|
||||||
|
|
||||||
# a super user can create variable objects
|
# a super user can create variable objects
|
||||||
|
|
||||||
@@ -186,6 +213,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a normal user with at least one inventory edit permission can create variable objects
|
# a normal user with at least one inventory edit permission can create variable objects
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# VARIABLES -> GROUPS
|
||||||
|
|
||||||
# a super user can associate variable objects with groups
|
# a super user can associate variable objects with groups
|
||||||
|
|
||||||
# an org admin can associate variable objects with groups
|
# an org admin can associate variable objects with groups
|
||||||
@@ -194,6 +224,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a normal user with inventory edit permissions can associate variable objects with groups
|
# a normal user with inventory edit permissions can associate variable objects with groups
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# VARIABLES -> HOSTS
|
||||||
|
|
||||||
# a super user can associate variable objects with hosts
|
# a super user can associate variable objects with hosts
|
||||||
|
|
||||||
# an org admin can associate variable objects with hosts
|
# an org admin can associate variable objects with hosts
|
||||||
@@ -202,6 +235,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a normal user with inventory edit permissions can associate variable objects with hosts
|
# a normal user with inventory edit permissions can associate variable objects with hosts
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# SUBGROUPS
|
||||||
|
|
||||||
# a super user can set subgroups
|
# a super user can set subgroups
|
||||||
|
|
||||||
# an org admin can set subgroups
|
# an org admin can set subgroups
|
||||||
@@ -210,6 +246,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a normal user with inventory edit permissions can associate subgroups
|
# a normal user with inventory edit permissions can associate subgroups
|
||||||
|
|
||||||
|
######################################################
|
||||||
|
# GROUP ACCESS
|
||||||
|
|
||||||
# a super user can get a group record
|
# a super user can get a group record
|
||||||
|
|
||||||
# an org admin can get a group record
|
# an org admin can get a group record
|
||||||
@@ -218,6 +257,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a regular user cannot read any group records
|
# a regular user cannot read any group records
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# HOST ACCESS
|
||||||
|
|
||||||
# a super user can get a host record
|
# a super user can get a host record
|
||||||
|
|
||||||
# an org admin can get a host record
|
# an org admin can get a host record
|
||||||
@@ -226,13 +268,19 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a regular user cannot get a host record
|
# a regular user cannot get a host record
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# GROUP VARIABLE ACCESS
|
||||||
|
|
||||||
# a super user can see the variables attached to a group
|
# a super user can see the variables attached to a group
|
||||||
|
|
||||||
# a org admin can see the variables attached to a group
|
# a org admin can see the variables attached to a group
|
||||||
|
|
||||||
# a user who is on a team who has read permissions on an inventory can see the variables attached to a group
|
# a user who is on a team who has read permissions on an inventory can see the variables attached to a group
|
||||||
|
|
||||||
# a regular user cannot get a host record
|
# a regular user cannot get a group variable record
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# HOST VARIABLE ACCESS
|
||||||
|
|
||||||
# a super user can see the variables attached to a host
|
# a super user can see the variables attached to a host
|
||||||
|
|
||||||
@@ -242,6 +290,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a regular user cannot see variables attached to a host
|
# a regular user cannot see variables attached to a host
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# GROUP CHILDREN ACCESS
|
||||||
|
|
||||||
# a super user can see the children attached to a group
|
# a super user can see the children attached to a group
|
||||||
|
|
||||||
# a org admin can see the children attached to a group
|
# a org admin can see the children attached to a group
|
||||||
@@ -250,6 +301,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a regular user cannot see children attached to a group
|
# a regular user cannot see children attached to a group
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# VARIABLE RESOURCE ACCESS
|
||||||
|
|
||||||
# a super user can see a variable record
|
# a super user can see a variable record
|
||||||
|
|
||||||
# an org admin can see a variable record
|
# an org admin can see a variable record
|
||||||
@@ -258,6 +312,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# a regular user cannot see a variable record
|
# a regular user cannot see a variable record
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# SUPER USER DISASSOCIATION
|
||||||
|
|
||||||
# a super user can disassociate...
|
# a super user can disassociate...
|
||||||
|
|
||||||
# hosts from inventory
|
# hosts from inventory
|
||||||
@@ -268,6 +325,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# the inventory task code returns valid inventory JSON.
|
# the inventory task code returns valid inventory JSON.
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# ORG ADMIN DISASSOCIATION
|
||||||
|
|
||||||
# an org admin user can disassociate...
|
# an org admin user can disassociate...
|
||||||
|
|
||||||
# hosts from inventory
|
# hosts from inventory
|
||||||
@@ -276,6 +336,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# subgroups from groups
|
# subgroups from groups
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# USER DISASSOCIATION
|
||||||
|
|
||||||
# a user with inventory edit permission disassociate...
|
# a user with inventory edit permission disassociate...
|
||||||
|
|
||||||
# hosts from inventory
|
# hosts from inventory
|
||||||
@@ -284,6 +347,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# subgroups from groups
|
# subgroups from groups
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# USER DISASSOCIATION (2)
|
||||||
|
|
||||||
# a regular user cannot disassociate....
|
# a regular user cannot disassociate....
|
||||||
|
|
||||||
# hosts from inventory
|
# hosts from inventory
|
||||||
@@ -292,6 +358,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# subgroups from inventory
|
# subgroups from inventory
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# TAGS
|
||||||
|
|
||||||
# the following objects can be tagged
|
# the following objects can be tagged
|
||||||
|
|
||||||
# inventory
|
# inventory
|
||||||
@@ -322,6 +391,9 @@ class InventoryTest(BaseTest):
|
|||||||
|
|
||||||
# variable records
|
# variable records
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
# RELATED FIELDS
|
||||||
|
|
||||||
# on an inventory resource, I can see related resources for hosts and groups and permissions
|
# on an inventory resource, I can see related resources for hosts and groups and permissions
|
||||||
# and these work
|
# and these work
|
||||||
|
|
||||||
|
|||||||
@@ -315,4 +315,37 @@ class HostsDetail(BaseDetail):
|
|||||||
serializer_class = HostSerializer
|
serializer_class = HostSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
|
class GroupsList(BaseList):
|
||||||
|
|
||||||
|
model = Group
|
||||||
|
serializer_class = GroupSerializer
|
||||||
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
|
def _get_queryset(self):
|
||||||
|
'''
|
||||||
|
I can see groups when:
|
||||||
|
I'm a superuser,
|
||||||
|
or an organization admin of an inventory they are in
|
||||||
|
or when I have allowing read permissions via a user or team on an inventory they are in
|
||||||
|
'''
|
||||||
|
base = Groups.objects
|
||||||
|
if self.request.user.is_superuser:
|
||||||
|
return base.all()
|
||||||
|
admin_of = base.filter(inventory__organization__admins__in = [ self.request.user ]).distinct()
|
||||||
|
has_user_perms = base.filter(
|
||||||
|
inventory__permissions__user__in = [ self.request.user ],
|
||||||
|
inventory__permissions__permission_type__in = PERMISSION_TYPES_ALLOWING_INVENTORY_READ,
|
||||||
|
).distinct()
|
||||||
|
has_team_perms = base.filter(
|
||||||
|
inventory__permissions__team__in = self.request.user.teams.all(),
|
||||||
|
inventory__permissions__permission_type__in = PERMISSION_TYPES_ALLOWING_INVENTORY_READ,
|
||||||
|
).distinct()
|
||||||
|
return admin_of | has_user_perms | has_team_perms
|
||||||
|
|
||||||
|
class GroupsDetail(BaseDetail):
|
||||||
|
|
||||||
|
model = Group
|
||||||
|
serializer_class = GroupSerializer
|
||||||
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ views_InventoryList = views.InventoryList.as_view()
|
|||||||
views_InventoryDetail = views.InventoryDetail.as_view()
|
views_InventoryDetail = views.InventoryDetail.as_view()
|
||||||
|
|
||||||
# group service
|
# group service
|
||||||
|
views_GroupsList = views.GroupsList.as_view()
|
||||||
|
views_GroupsDetail = views.GroupsDetail.as_view()
|
||||||
|
|
||||||
# host service
|
# host service
|
||||||
views_HostsList = views.HostsList.as_view()
|
views_HostsList = views.HostsList.as_view()
|
||||||
@@ -99,6 +101,8 @@ urlpatterns = patterns('',
|
|||||||
url(r'^api/v1/hosts/(?P<pk>[0-9]+)/$', views_HostsDetail),
|
url(r'^api/v1/hosts/(?P<pk>[0-9]+)/$', views_HostsDetail),
|
||||||
|
|
||||||
# group service
|
# group service
|
||||||
|
url(r'^api/v1/groups/$', views_GroupsList),
|
||||||
|
url(r'^api/v1/groups/(?P<pk>[0-9]+)/$', views_GroupsDetail),
|
||||||
|
|
||||||
# inventory variable service
|
# inventory variable service
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user