integrating new tables
[plcapi.git] / PLC / Sites.py
1 from types import StringTypes
2 from datetime import datetime
3 import string
4
5 from PLC.Faults import *
6 from PLC.Logger import logger
7 from PLC.Parameter import Parameter, Mixed
8 from PLC.Storage.AlchemyObject import AlchemyObj
9 from PLC.Slices import Slice, Slices
10 from PLC.Persons import Person, Persons
11 from PLC.SitePersons import SitePerson, SitePersons
12 from PLC.SiteAddresses import SiteAddress, SiteAddress
13 from PLC.PCUs import PCU, PCUs
14 from PLC.Nodes import Node, Nodes
15 from PLC.Roles import Role, Roles
16 from PLC.SiteTags import SiteTag, SiteTags
17
18 class Site(AlchemyObj):
19     """
20     Representation of a row in the sites table. To use, optionally
21     instantiate with a dict of values. Update as you would a
22     dict. Commit to the database with sync().
23     """
24
25     tablename = 'sites'
26
27     fields = {
28         'site_id': Parameter(int, "Site identifier", primary_key=True),
29         'tenant_id': Parameter(str, "Tenant identifier"),
30         'enabled': Parameter(bool, "Has been enabled"),
31         'abbreviated_name': Parameter(str, "Abbreviated site name", max = 50),
32         'login_base': Parameter(str, "Site slice prefix", max = 20),
33         'is_public': Parameter(bool, "Publicly viewable site"),
34         'name': Parameter(str, "Full site name", max = 254),
35         'description': Parameter(str, "Description", max = 254),
36         'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0, nullok = True),
37         'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0, nullok = True),
38         'url': Parameter(str, "URL of a page that describes the site", max = 254, nullok = True),
39         'date_created': Parameter(datetime, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True, default=datetime.now()), 
40         'last_updated': Parameter(datetime, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True, nullok=True), 
41         'max_slices': Parameter(int, "Maximum number of slices that the site is able to create", default=10),
42         'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create", default=1000),
43         'person_ids': Parameter([int], "List of account identifiers", joined=True),
44         'slice_ids': Parameter([int], "List of slice identifiers", joined=True),
45         'address_ids': Parameter([int], "List of address identifiers", joined=True),
46         'pcu_ids': Parameter([int], "List of PCU identifiers", joined=True),
47         'node_ids': Parameter([int], "List of site node identifiers", joined=True),
48         'site_tag_ids' : Parameter ([int], "List of tags attached to this site", joined=True),
49         'peer_id': Parameter(int, "Peer to which this site belongs", nullok = True),
50         'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True),
51         'ext_consortium_id': Parameter(int, "external consortium id", nullok = True) 
52         }
53
54     def validate_last_updated(self, last_updated):
55         # always return current timestamp 
56         last_updated = datetime.now()
57         return last_updated
58
59     def add_person(self, person_filter, role_name=None):
60         assert 'site_id' in self
61         assert 'tenant_id' in self
62         if not role_name:
63             role_name = 'user'
64         roles = Roles(self.api, role_name)
65         if not roles:
66             raise PLCInvalidArgument, "No such role %s" % role_name
67         role = roles[0]
68         tenant = self.api.client_shell.keystone.tenants.find(id=self['tenant_id']) 
69         persons = Persons(self.api, person_filter)
70         for person in persons:
71             keystone_user = self.api.client_shell.keystone.users.find(id=person['keystone_id'])
72             tenant.add_user(keystone_user, role.object)  
73             site_person = SitePerson(self.api, {'site_id': self['site_id'], 
74                                                 'person_id': person['person_id']}) 
75             site_person.sync()
76
77
78     def delete_person(self, person_filter, role=None):
79         assert 'site_id' in self
80         assert 'tenant_id' in self
81         if not role:
82             role = 'user'
83         roles = Roles(self.api, role_name)
84         if not roles:
85             raise PLCInvalidArgument, "No such role %s" % role_name
86         role = roles[0]
87         tenant = self.api.client_shell.keystone.tenants.find(id=self['tenant_id'])
88         persons = Persons(self.api, person_filter)
89         for person in persons:
90             keystone_user = self.api.client_shell.keystone.users.find(id=person['keystone_id'])
91             tenant.remove_user(keystone_user, role.object)
92             site_persons = SitePersons(self.api, {'site_id': self['id'],
93                                                 'person_id': person['person_id']})
94             for site_person in site_persons:
95                 site_person.delete()    
96           
97
98     def sync(self, commit=True, validate=True):
99         """
100         Add or update the site.
101         """
102         assert 'login_base' in self
103         AlchemyObj.sync(self, commit=commit, validate=validate)     
104         # filter out fields that are not supported in keystone
105         nova_fields = ['enabled', 'description']
106         nova_can_update = lambda (field, value): field in nova_fields
107         nova_site = dict(filter(nova_can_update, self.items()))
108         nova_site['tenant_name'] = self['login_base']
109         if 'site_id' not in self:
110             # check if keystone record exsits
111             tenants = self.api.client_shell.keystone.tenants.findall(name=self['login_base'])
112             if not tenants:
113                 self.object = self.api.client_shell.keystone.tenants.create(**nova_site)
114             else:
115                 self.object = tenants[0]
116             self['tenant_id'] = self.object.id
117             # sync the plc record
118             AlchemyObj.insert(self, dict(self))
119             site = AlchemyObj.select(self, filter={'tenant_id': self['tenant_id']})[0]
120             self['site_id'] = site.site_id
121              
122         else:
123             self.object = self.api.client_shell.keystone.tenants.update(self['tenant_id'], **nova_site)
124             AlchemyObj.update(self, {'site_id': self['site_id']}, dict(self))
125
126     def delete(self, commit=True):
127         assert 'site_id' in self
128         assert 'tenant_id' in self
129         
130         # delete nova object
131         tenant = self.api.client_shell.keystone.tenants.find(id=self['tenant_id'])
132         self.api.client_shell.keystone.tenants.delete(tenant)
133         
134         # delete relationships
135         for site_person in SitePerson().select(filter={'site_id': self['site_id']}):
136             site_person.delete()
137         for slice in Slice().select(filter={'site_id': self['site_id']}):
138             slice.delete()
139         for pcu in PCU().select(filter={'site_id': self['site_id']}):
140             pcu.delete()
141         for node in Node().select(filter={'site_id': self['site_id']}):
142             node.delete()
143         for address in SiteAddress().select(filter={'site_id': self['site_id']}):
144             address.delete()
145         for site_tag in SiteTag().select(filter={'site_id': self['site_id']}):
146             site_tag.delete() 
147         
148         # delete site
149         AlchemyObj.delete(self, filter={'site_id': self['site_id']})        
150         
151                
152
153 class Sites(list):
154     """
155     Representation of row(s) from the sites table in the
156     database.
157     """
158
159     def __init__(self, api, site_filter = None, columns = None):
160         self.api = api 
161         if not site_filter:
162             sites = Site().select() 
163         elif isinstance(site_filter, int):
164             sites = Site().select(filter={'site_id': site_filter})
165         elif isinstance(site_filter, StringTypes):
166             sites = Site().select(filter={'login_base': site_filter})
167         elif isinstance(site_filter, dict):
168             sites = Site().select(filter=site_filter)
169         elif isinstance(site_filter, (list, tuple, set)):
170             ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
171             strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
172             site_filter = {'site_id': ints, 'login_base': strs}
173             sites = Site().select(filter=site_filter)
174         else:
175             raise PLCInvalidArgument, "Wrong site filter %s" % site_filter         
176
177
178         for site in sites:
179             site = Site(self.api, object = site)
180             if not columns or 'person_ids' in columns:
181                 site_persons = SitePerson().select(filter={'site_id': site['site_id']})
182                 site['person_ids'] = [rec.person_id for rec in site_persons]
183
184             if not columns or 'slice_ids' in columns:
185                 site_slices = Slice().select(filter={'site_id': site['site_id']})
186                 site['slice_ids'] = [rec.slice_id for rec in site_slices]
187
188             if not columns or 'puc_ids' in columns:
189                 site_pcus = PCU().select(filter={'site_id': site['site_id']})
190                 site['pcu_ids'] = [rec.pcu_id for rec in site_pcus]
191             if not columns or 'node_ids' in columns:
192                 site_nodes = Node().select(filter={'site_id': site['site_id']})
193                 site['node_ids'] = [rec.node_id for rec in site_nodes]
194             if not columns or 'address_ids' in columns:
195                 site_addresses = SiteAddress().select(filter={'site_id': site['site_id']})
196                 site['address_ids'] = [rec.address_id for rec in site_addresses]
197
198             if not columns or 'site_tag_ids' in columns:
199                 site_tags = SiteTag().select(filter={'site_id': site['site_id']})
200                 site['site_tag_ids'] = [rec.tag_id for rec in site_tags]
201
202             self.append(site)