Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
[plstackapi.git] / planetstack / openstack_observer / steps / sync_slivers.py
1 import os
2 import base64
3 from django.db.models import F, Q
4 from planetstack.config import Config
5 from observer.openstacksyncstep import OpenStackSyncStep
6 from core.models.sliver import Sliver
7 from core.models.slice import Slice, SlicePrivilege, ControllerSlice
8 from core.models.network import Network, NetworkSlice, ControllerNetwork
9 from util.logger import Logger, logging
10 from observer.ansible import *
11
12 logger = Logger(level=logging.INFO)
13
14 def escape(s):
15     s = s.replace('\n',r'\n').replace('"',r'\"')
16     return s
17
18 class SyncSlivers(OpenStackSyncStep):
19     provides=[Sliver]
20     requested_interval=0
21
22     def get_userdata(self, sliver):
23         userdata = 'opencloud:\n   slicename: "%s"\n   hostname: "%s"\n' % (sliver.slice.name, sliver.node.name)
24         return userdata
25
26     def sync_record(self, sliver):
27         logger.info("sync'ing sliver:%s slice:%s controller:%s " % (sliver, sliver.slice.name, sliver.node.site_deployment.controller))
28
29         metadata_update = {}
30         if (sliver.numberCores):
31             metadata_update["cpu_cores"] = str(sliver.numberCores)
32
33         for tag in sliver.slice.tags.all():
34             if tag.name.startswith("sysctl-"):
35                 metadata_update[tag.name] = tag.value
36
37         # public keys
38         slice_memberships = SlicePrivilege.objects.filter(slice=sliver.slice)
39         pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
40         if sliver.creator.public_key:
41             pubkeys.add(sliver.creator.public_key)
42
43         if sliver.slice.creator.public_key:
44             pubkeys.add(sliver.slice.creator.public_key)
45
46         nics = []
47         networks = [ns.network for ns in NetworkSlice.objects.filter(slice=sliver.slice)]
48         controller_networks = ControllerNetwork.objects.filter(network__in=networks,
49                                                                 controller=sliver.node.site_deployment.controller)
50
51         for controller_network in controller_networks:
52             if controller_network.network.template.visibility == 'private' and \
53                controller_network.network.template.translation == 'none' and controller_network.net_id:
54                 nics.append(controller_network.net_id)
55
56         # now include network template
57         network_templates = [network.template.shared_network_name for network in networks \
58                              if network.template.shared_network_name]
59
60         #driver = self.driver.client_driver(caller=sliver.creator, tenant=sliver.slice.name, controller=sliver.controllerNetwork)
61         driver = self.driver.admin_driver(tenant='admin', controller=sliver.node.site_deployment.controller)
62         nets = driver.shell.quantum.list_networks()['networks']
63         for net in nets:
64             if net['name'] in network_templates:
65                 nics.append(net['id'])
66
67         if (not nics):
68             for net in nets:
69                 if net['name']=='public':
70                     nics.append(net['id'])
71
72         # look up image id
73         controller_driver = self.driver.admin_driver(controller=sliver.node.site_deployment.controller)
74         image_id = None
75         images = controller_driver.shell.glanceclient.images.list()
76         for image in images:
77             if image.name == sliver.image.name or not image_id:
78                 image_id = image.id
79
80         # look up key name at the controller
81         # create/fetch keypair
82         keyname = None
83         keyname = sliver.creator.email.lower().replace('@', 'AT').replace('.', '') +\
84                   sliver.slice.name
85         key_fields =  {'name': keyname,
86                        'public_key': sliver.creator.public_key}
87
88         try:
89             legacy = Config().observer_legacy
90         except:
91             legacy = False
92
93         if (legacy):
94             host_filter = sliver.node.name.split('.',1)[0]
95         else:
96             host_filter = sliver.node.name.strip()
97
98         availability_zone_filter = 'nova:%s'%host_filter
99         sliver_name = '%s-%d'%(sliver.slice.name,sliver.id)
100
101         userData = self.get_userdata(sliver)
102         if sliver.userData:
103             userData = sliver.userData
104
105         controller = sliver.node.site_deployment.controller
106         tenant_fields = {'endpoint':controller.auth_url,
107                      'admin_user': sliver.creator.email,
108                      'admin_password': sliver.creator.remote_password,
109                      'admin_tenant': sliver.slice.name,
110                      'tenant': sliver.slice.name,
111                      'tenant_description': sliver.slice.description,
112                      'name':sliver_name,
113                      'ansible_tag':sliver_name,
114                      'availability_zone': availability_zone_filter,
115                      'image_id':image_id,
116                      'key_name':keyname,
117                      'flavor_id':sliver.flavor.id,
118                      'nics':nics,
119                      'meta':metadata_update,
120                      'key':key_fields,
121                      'user_data':r'%s'%escape(userData)}
122
123         res = run_template('sync_slivers.yaml', tenant_fields,path='slivers')
124         if (len(res)!=2):
125             raise Exception('Could not sync sliver %s'%sliver.slice.name)
126         else:
127             sliver_id = res[1]['info']['OS-EXT-SRV-ATTR:instance_name'] # 0 is for the key
128             sliver_uuid = res[1]['id'] # 0 is for the key
129
130             try:
131                 hostname = res[1]['info']['OS-EXT-SRV-ATTR:hypervisor_hostname']
132                 ip = socket.gethostbyname(hostname)
133                 sliver.ip = ip
134             except:
135                 pass
136
137             sliver.instance_id = sliver_id
138             sliver.instance_uuid = sliver_uuid
139             sliver.instance_name = sliver_name
140             sliver.save()
141
142     def delete_record(self, sliver):
143         sliver_name = '@'.join([sliver.slice.name,sliver.node.name])
144         tenant_fields = {'name':sliver_name,
145                          'ansible_tag':sliver_name
146                         }
147         res = run_template('delete_slivers.yaml', tenant_fields, path='slivers')