delete_tenant() deletes all instances associated with the specified tenant
[plstackapi.git] / planetstack / openstack / driver.py
1 import commands
2 from planetstack.config import Config
3 from openstack.client import OpenStackClient
4
5 class OpenStackDriver:
6
7     def __init__(self, config = None, client=None): 
8         if config:
9             self.config = Config(config)
10         else:
11             self.config = Config() 
12
13         self.admin_client = OpenStackClient()
14         self.admin_user = self.admin_client.keystone.users.find(name=self.admin_client.keystone.username)
15
16         if client:
17             self.shell = client
18         else:
19             self.shell = OpenStackClient()
20
21     def create_role(self, name): 
22         roles = self.shell.keystone.roles.findall(name=name)
23         if not roles:
24             role = self.shell.keystone.roles.create(name)
25         else:
26             role = roles[0] 
27         return role
28
29     def delete_role(self, filter):
30         roles = self.shell.keystone.roles.findall(**filter)
31         for role in roles:
32             self.shell.keystone.roles.delete(role)
33         return 1
34
35     def create_tenant(self, tenant_name, enabled, description):
36         """Create keystone tenant. Suggested fields: name, description, enabled"""  
37         tenants = self.shell.keystone.tenants.findall(name=tenant_name)
38         if not tenants:
39             fields = {'tenant_name': tenant_name, 'enabled': enabled, 
40                       'description': description}  
41             tenant = self.shell.keystone.tenants.create(**fields)
42         else:
43             tenant = tenants[0]
44
45         # always give the admin user the admin role to any tenant created 
46         # by the driver. 
47         self.add_user_role(self.admin_user.id, tenant.id, 'admin')
48         return tenant
49
50     def update_tenant(self, id, **kwds):
51         return self.shell.keystone.tenants.update(id, **kwds)
52
53     def delete_tenant(self, id):
54         ctx = self.shell.nova_db.ctx
55         tenants = self.shell.keystone.tenants.findall(id=id)
56         for tenant in tenants:
57             # nova does not automatically delete the tenant's instances
58             # so we manually delete instances before deleteing the tenant   
59             instances = self.shell.nova_db.instance_get_all_by_filters(ctx, 
60                        {'project_id': tenant.id}, 'id', 'asc')
61             client = OpenStackClient(tenant=tenant)
62             driver = OpenStackDriver(client=client)
63             for instance in instances:
64                 driver.destroy_instance(instance.id)
65             self.shell.keystone.tenants.delete(tenant)
66         return 1
67
68     def create_user(self, name, email, password, enabled):
69         users = self.shell.keystone.users.findall(email=email)
70         if not users:
71             fields = {'name': name, 'email': email, 'password': password,
72                       'enabled': enabled}
73             user = self.shell.keystone.users.create(**fields)
74         else: 
75             user = users[0]
76         return user
77
78     def delete_user(self, id):
79         users = self.shell.keystone.users.findall(id=id)
80         for user in users:
81             # delete users keys
82             keys = self.shell.nova.keypairs.findall()
83             for key in keys:
84                 self.shell.nova.keypairs.delete(key)
85             self.shell.keystone.users.delete(user)
86         return 1 
87
88     def add_user_role(self, kuser_id, tenant_id, role_name):
89         user = self.shell.keystone.users.find(id=kuser_id)
90         tenant = self.shell.keystone.tenants.find(id=tenant_id)
91         role = self.shell.keystone.roles.find(name=role_name)
92
93         role_found = False
94         user_roles = user.list_roles(tenant.id)
95         for user_role in user_roles:
96             if user_role.name == role.name:
97                 role_found = True
98         if not role_found:
99             tenant.add_user(user, role)
100
101         return 1
102
103     def delete_user_role(self, kuser_id, tenant_id, role_name):
104         user = self.shell.keystone.users.find(id=kuser_id)
105         tenant = self.shell.keystone.tenants.find(id=tenant_id)
106         role = self.shell.keystone.roles.find(name=role_name)
107
108         role_found = False
109         user_roles = user.list_roles(tenant.id)
110         for user_role in user_roles:
111             if user_role.name == role.name:
112                 role_found = True
113         if role_found:
114             tenant.remove_user(user, role)
115
116         return 1 
117
118     def update_user(self, id, fields):
119         if 'password' in fields:
120             self.shell.keystone.users.update_password(id, fields['password'])
121         if 'enabled' in fields:
122             self.shell.keystone.users.update_enabled(id, fields['enabled']) 
123         return 1 
124
125     def create_router(self, name, set_gateway=True):
126         routers = self.shell.quantum.list_routers(name=name)['routers']
127         if routers:
128             router = routers[0]
129         else:
130             router = self.shell.quantum.create_router({'router': {'name': name}})['router']
131         # add router to external network
132         if set_gateway:
133             nets = self.shell.quantum.list_networks()['networks']
134             for net in nets:
135                 if net['router:external'] == True: 
136                     self.shell.quantum.add_gateway_router(router['id'],
137                                                           {'network_id': net['id']})
138         
139         return router
140
141     def delete_router(self, id):
142         routers = self.shell.quantum.list_routers(id=id)['routers']
143         for router in routers:
144             self.shell.quantum.delete_router(router['id'])
145             # remove router form external network
146             #nets = self.shell.quantum.list_networks()['networks']
147             #for net in nets:
148             #    if net['router:external'] == True:
149             #        self.shell.quantum.remove_gateway_router(router['id'])
150
151     def add_router_interface(self, router_id, subnet_id):
152         router = self.shell.quantum.show_router(router_id)['router']
153         subnet = self.shell.quantum.show_subnet(subnet_id)['subnet']
154         if router and subnet:
155             self.shell.quantum.add_interface_router(router_id, {'subnet_id': subnet_id})
156
157     def delete_router_interface(self, router_id, subnet_id):
158         router = self.shell.quantum.show_router(router_id)
159         subnet = self.shell.quantum.show_subnet(subnet_id)
160         if router and subnet:
161             self.shell.quantum.remove_interface_router(router_id, {'subnet_id': subnet_id})
162  
163     def create_network(self, name):
164         nets = self.shell.quantum.list_networks(name=name)['networks']
165         if nets: 
166             net = nets[0]
167         else:
168             net = self.shell.quantum.create_network({'network': {'name': name}})['network']
169         return net
170  
171     def delete_network(self, id):
172         nets = self.shell.quantum.list_networks()['networks']
173         for net in nets:
174             if net['id'] == id:
175                 # delete_all ports
176                 self.delete_network_ports(net['id'])
177                 # delete all subnets:
178                 for subnet_id in net['subnets']:
179                     self.delete_subnet(subnet_id)
180                 self.shell.quantum.delete_network(net['id'])
181         return 1
182
183     def delete_network_ports(self, network_id):
184         ports = self.shell.quantum.list_ports()['ports']
185         for port in ports:
186             if port['network_id'] == network_id:
187                 self.shell.quantum.delete_port(port['id'])
188         return 1         
189
190     def delete_subnet_ports(self, subnet_id):
191         ports = self.shell.quantum.list_ports()['ports']
192         for port in ports:
193             delete = False
194             for fixed_ip in port['fixed_ips']:
195                 if fixed_ip['subnet_id'] == subnet_id:
196                     delete=True
197                     break
198             if delete:
199                 self.shell.quantum.delete_port(port['id'])
200         return 1
201  
202     def create_subnet(self, name, network_id, cidr_ip, ip_version, start, end):
203         #nets = self.shell.quantum.list_networks(name=network_name)['networks']
204         #if not nets:
205         #    raise Exception, "No such network: %s" % network_name   
206         #net = nets[0]
207
208         subnet = None 
209         subnets = self.shell.quantum.list_subnets()['subnets']
210         for snet in subnets:
211             if snet['cidr'] == cidr_ip and snet['network_id'] == network_id:
212                 subnet = snet
213  
214         if not subnet:
215             allocation_pools = [{'start': start, 'end': end}]
216             subnet = {'subnet': {'name': name,
217                                  'network_id': network_id,
218                                  'ip_version': ip_version,
219                                  'cidr': cidr_ip,
220                                  'dns_nameservers': ['8.8.8.8', '8.8.4.4'],
221                                  'allocation_pools': allocation_pools}}          
222             subnet = self.shell.quantum.create_subnet(subnet)['subnet']
223             self.add_external_route(subnet)
224         # TODO: Add route to external network
225         # e.g. #  route add -net 10.0.3.0/24 dev br-ex gw 10.100.0.5 
226         return subnet
227
228     def update_subnet(self, id, fields):
229         return self.shell.quantum.update_subnet(id, fields)
230
231     def delete_subnet(self, id):
232         #return self.shell.quantum.delete_subnet(id=id)
233         # inefficient but fault tolerant
234         subnets = self.shell.quantum.list_subnets()['subnets']
235         for subnet in subnets:
236             if subnet['id'] == id:
237                 self.delete_subnet_ports(subnet['id'])
238                 self.shell.quantum.delete_subnet(id)
239                 self.delete_external_route(subnet)
240         return 1
241
242     def add_external_route(self, subnet):
243         ports = self.shell.quantum.list_ports()['ports']
244
245         gw_ip = subnet['gateway_ip']
246         subnet_id = subnet['id']
247
248         # 1. Find the port associated with the subnet's gateway
249         # 2. Find the router associated with that port
250         # 3. Find the port associated with this router and on the external net
251         # 4. Set up route to the subnet through the port from step 3
252         ip_address = None
253         for port in ports:
254             for fixed_ip in port['fixed_ips']:
255                 if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
256                     gw_port = port
257                     router_id = gw_port['device_id']
258                     router = self.shell.quantum.show_router(router_id)['router']
259                     ext_net = router['external_gateway_info']['network_id']
260                     for port in ports:
261                         if port['device_id'] == router_id and port['network_id'] == ext_net:
262                             ip_address = port['fixed_ips'][0]['ip_address']
263
264         if ip_address:
265             cmd = "route add -net %s dev br-ex gw %s" % (subnet['cidr'], ip_address)
266             commands.getstatusoutput(cmd)
267
268         return 1
269
270     def delete_external_route(self, subnet):
271         ports = self.shell.quantum.list_ports()['ports']
272
273         gw_ip = subnet['gateway_ip']
274         subnet_id = subnet['id']
275
276         # 1. Find the port associated with the subnet's gateway
277         # 2. Find the router associated with that port
278         # 3. Find the port associated with this router and on the external net
279         # 4. Set up route to the subnet through the port from step 3
280         ip_address = None
281         for port in ports:
282             for fixed_ip in port['fixed_ips']:
283                 if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
284                     gw_port = port
285                     router_id = gw_port['device_id']
286                     router = self.shell.quantum.show_router(router_id)['router']
287                     ext_net = router['external_gateway_info']['network_id']
288                     for port in ports:
289                         if port['device_id'] == router_id and port['network_id'] == ext_net:
290                             ip_address = port['fixed_ips'][0]['ip_address']
291
292         if ip_address:
293             cmd = "route delete -net %s" % (subnet['cidr'])
294             commands.getstatusoutput(cmd)
295              
296         return 1
297     
298     def create_keypair(self, name, public_key):
299         keys = self.shell.nova.keypairs.findall(name=name)
300         if keys:
301             key = keys[0]
302             # update key     
303             if key.public_key != public_key:
304                 self.delete_keypair(key.id)
305                 key = self.shell.nova.keypairs.create(name=name, public_key=public_key)
306         else:
307             key = self.shell.nova.keypairs.create(name=name, public_key=public_key)
308         return key
309
310     def delete_keypair(self, id):
311         keys = self.shell.nova.keypairs.findall(id=id)
312         for key in keys:
313             self.shell.nova.keypairs.delete(key) 
314         return 1 
315
316     def spawn_instance(self, name, key_name=None, hostname=None, image_id=None, security_group=None, pubkeys=[]):
317         flavor_name = self.config.nova_default_flavor
318         flavor = self.shell.nova.flavors.find(name=flavor_name)
319         #if not image:
320         #    image = self.config.nova_default_imave
321         if not security_group:
322             security_group = self.config.nova_default_security_group 
323
324         files = {}
325         if pubkeys:    
326             files['/root/.ssh/authorized_keys'] = "\n".join(pubkeys)
327        
328         hints = {}
329         availability_zone = None
330         if hostname:
331             availability_zone = 'nova:%s' % hostname
332         server = self.shell.nova.servers.create(
333                                             name=name,
334                                             key_name = key_name,
335                                             flavor=flavor.id,
336                                             image=image_id,
337                                             security_group = security_group,
338                                             files=files,
339                                             scheduler_hints=hints,
340                                             availability_zone=availability_zone)
341         return server
342           
343     def destroy_instance(self, id):
344         servers = self.shell.nova.servers.findall(id=id)
345         for server in servers:
346             self.shell.nova.servers.delete(server)
347
348     def update_instance_metadata(self, id, metadata):
349         servers = self.shell.nova.servers.findall(id=id)
350         for server in servers:
351             self.shell.nova.servers.set_meta(server, metadata)
352             # note: set_meta() returns a broken Server() object. Don't try to
353             # print it in the shell or it will fail in __repr__.
354
355     def delete_instance_metadata(self, id, metadata):
356         # note: metadata is a dict. Only the keys matter, not the values.
357         servers = self.shell.nova.servers.findall(id=id)
358         for server in servers:
359             self.shell.nova.servers.delete_meta(server, metadata)
360