plumb numberCores attribute through to nova metadata
[plstackapi.git] / plstackapi / openstack / manager.py
1 from plstackapi.planetstack import settings
2 from django.core import management
3 management.setup_environ(settings)
4 try:
5     from plstackapi.openstack.client import OpenStackClient
6     from plstackapi.openstack.driver import OpenStackDriver
7     from plstackapi.planetstack.config import Config
8     from plstackapi.core.models import * 
9     has_openstack = True
10 except:
11     has_openpstack = False
12
13 manager_enabled = Config().api_nova_enabled
14
15 def require_enabled(callable):
16     def wrapper(*args, **kwds):
17         if manager_enabled and has_openstack:
18             return callable(*args, **kwds)
19         else:
20             return None
21     return wrapper
22
23
24 class OpenStackManager:
25
26     def __init__(self, auth={}, caller=None):
27         self.client = None
28         self.driver = None
29         self.caller = None
30         self.has_openstack = has_openstack       
31         self.enabled = manager_enabled
32
33         if has_openstack and manager_enabled:
34             if auth:
35                 self.client = OpenStackClient(**auth)
36             else:
37                 self.client = OpenStackClient()
38             self.driver = OpenStackDriver(client=self.client) 
39             
40             if caller:
41                 self.caller = caller
42             else:
43                 self.caller = self.driver.admin_user
44                 self.caller.user_id = self.caller.id 
45
46     @require_enabled
47     def save_role(self, role):
48         if not role.role_id:
49             keystone_role = self.driver.create_role(role.role_type)
50             role.role_id = keystone_role.id
51
52     @require_enabled
53     def delete_role(self, role):
54         if role.role_id:
55             self.driver.delete_role({'id': role.role_id})
56
57     @require_enabled
58     def save_key(self, key):
59         if not key.key_id:
60             key_fields = {'name': key.name,
61                           'key': key.key}
62             nova_key = self.driver.create_keypair(**key_fields)
63             key.key_id = nova_key.id        
64
65     @require_enabled
66     def delete_key(self, key):
67         if key.key_id:
68             self.driver.delete_keypair(key.key_id)
69
70     @require_enabled
71     def save_user(self, user):
72         if not user.user_id:
73             name = user.email[:user.email.find('@')]
74             user_fields = {'name': name,
75                            'email': user.email,
76                            'password': user.password,
77                            'enabled': True}
78             keystone_user = self.driver.create_user(**user_fields)
79             user.user_id = keystone_user.id
80         if user.site:
81             if user.is_admin:
82                 role = 'admin'
83             else:
84                 role = 'user'       
85             self.driver.add_user_role(user.user_id, user.site.tenant_id, role)
86   
87     @require_enabled
88     def delete_user(self, user):
89         if user.user_id:
90             self.driver.delete_user(user.user_id)        
91     
92
93     
94     @require_enabled
95     def save_site(self, site, add_role=True):
96         if not site.tenant_id:
97             tenant = self.driver.create_tenant(tenant_name=site.login_base,
98                                                description=site.name,
99                                                enabled=site.enabled)
100             site.tenant_id = tenant.id
101             # give caller an admin role at the tenant they've created
102             self.driver.add_user_role(self.caller.user_id, tenant.id, 'admin')
103
104         # update the record
105         if site.id and site.tenant_id:
106             self.driver.update_tenant(site.tenant_id,
107                                       description=site.name,
108                                       enabled=site.enabled)
109
110     @require_enabled
111     def delete_site(self, site):
112         if site.tenant_id:
113             self.driver.delete_tenant(site.tenant_id)
114                
115     @require_enabled
116     def save_slice(self, slice):
117         if not slice.tenant_id:
118             nova_fields = {'tenant_name': slice.name,
119                    'description': slice.description,
120                    'enabled': slice.enabled}
121             tenant = self.driver.create_tenant(**nova_fields)
122             slice.tenant_id = tenant.id
123
124             # give caller an admin role at the tenant they've created
125             self.driver.add_user_role(self.caller.user_id, tenant.id, 'admin')
126
127             # refresh credentials using this tenant
128             self.driver.shell.connect(username=self.driver.shell.keystone.username,
129                                       password=self.driver.shell.keystone.password,
130                                       tenant=tenant.name)
131
132             # create network
133             network = self.driver.create_network(slice.name)
134             slice.network_id = network['id']
135
136             # create router
137             router = self.driver.create_router(slice.name)
138             slice.router_id = router['id']
139
140         if slice.id and slice.tenant_id:
141             self.driver.update_tenant(slice.tenant_id,
142                                       description=slice.description,
143                                       enabled=slice.enabled)    
144
145     @require_enabled
146     def delete_slice(self, slice):
147         if slice.tenant_id:
148             self.driver.delete_router(slice.router_id)
149             self.driver.delete_network(slice.network_id)
150             self.driver.delete_tenant(slice.tenant_id)
151
152     @require_enabled
153     def save_subnet(self, subnet):    
154         if not subnet.subnet_id:
155             quantum_subnet = self.driver.create_subnet(name= subnet.slice.name,
156                                           network_id=subnet.slice.network_id,
157                                           cidr_ip = subnet.cidr,
158                                           ip_version=subnet.ip_version,
159                                           start = subnet.start,
160                                           end = subnet.end)
161             subnet.subnet_id = quantum_subnet['id']
162             # add subnet as interface to slice's router
163             self.driver.add_router_interface(subnet.slice.router_id, subnet.subnet_id)
164             #add_route = 'route add -net %s dev br-ex gw 10.100.0.5' % self.cidr
165             #commands.getstatusoutput(add_route)
166
167     
168     @require_enabled
169     def delete_subnet(self, subnet):
170         if subnet.subnet_id:
171             self.driver.delete_router_interface(subnet.slice.router_id, subnet.subnet_id)
172             self.driver.delete_subnet(subnet.subnet_id)
173             #del_route = 'route del -net %s' % self.cidr
174             #commands.getstatusoutput(del_route)
175
176     @require_enabled
177     def save_sliver(self, sliver):
178         if not sliver.instance_id:
179             instance = self.driver.spawn_instance(name=sliver.name,
180                                    key_name = sliver.key.name,
181                                    image_id = sliver.image.image_id,
182                                    hostname = sliver.node.name )
183             sliver.instance_id = instance.id
184             sliver.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
185
186         if sliver.instance_id:
187             self.driver.update_instance_metadata(sliver.instance_id, {"cpu_cores": str(sliver.numberCores)})
188
189     @require_enabled
190     def delete_sliver(self, sliver):
191         if sliver.instance_id:
192             self.driver.destroy_instance(sliver.instance_id) 
193     
194
195     def refresh_nodes(self):
196         # collect local nodes
197         nodes = Node.objects.all()
198         nodes_dict = {}
199         for node in nodes:
200             if 'viccidev10' not in node.name:
201                 nodes_dict[node.name] = node 
202         
203         deployment = DeploymentNetwork.objects.filter(name='VICCI')[0]
204         login_bases = ['princeton', 'stanford', 'gt', 'uw', 'mpisws']
205         sites = Site.objects.filter(login_base__in=login_bases)
206         # collect nova nodes:
207         compute_nodes = self.client.nova.hypervisors.list()
208
209         compute_nodes_dict = {}
210         for compute_node in compute_nodes:
211             compute_nodes_dict[compute_node.hypervisor_hostname] = compute_node
212
213         # add new nodes:
214         new_node_names = set(compute_nodes_dict.keys()).difference(nodes_dict.keys())
215         i = 0
216         max = len(sites)
217         for name in new_node_names:
218             if i == max:
219                 i = 0
220             site = sites[i]
221             node = Node(name=compute_nodes_dict[name].hypervisor_hostname,
222                         site=site,
223                         deploymentNetwork=deployment)
224             node.save()
225             i+=1
226
227         # remove old nodes
228         old_node_names = set(nodes_dict.keys()).difference(compute_nodes_dict.keys())
229         Node.objects.filter(name__in=old_node_names).delete()
230
231     def refresh_images(self):
232         # collect local images
233         images = Image.objects.all()
234         images_dict = {}    
235         for image in images:
236             images_dict[image.name] = image
237
238         # collect glance images
239         glance_images = self.client.glance.get_images()
240         glance_images_dict = {}
241         for glance_image in glance_images:
242             glance_images_dict[glance_image['name']] = glance_image
243
244         # add new images
245         new_image_names = set(glance_images_dict.keys()).difference(images_dict.keys())
246         for name in new_image_names:
247             image = Image(image_id=glance_images_dict[name]['id'],
248                           name=glance_images_dict[name]['name'],
249                           disk_format=glance_images_dict[name]['disk_format'],
250                           container_format=glance_images_dict[name]['container_format'])
251             image.save()
252
253         # remove old images
254         old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
255         Image.objects.filter(name__in=old_image_names).delete()
256
257