7 from collections import defaultdict
8 from nova.exception import ImageNotFound
9 from nova.api.ec2.cloud import CloudController
10 from sfa.util.faults import SfaAPIError
11 from sfa.rspecs.rspec import RSpec
12 from sfa.rspecs.elements.hardware_type import HardwareType
13 from sfa.rspecs.elements.node import Node
14 from sfa.rspecs.elements.sliver import Sliver
15 from sfa.rspecs.elements.login import Login
16 from sfa.rspecs.elements.disk_image import DiskImage
17 from sfa.rspecs.elements.services import Services
18 from sfa.rspecs.elements.interface import Interface
19 from sfa.util.xrn import Xrn
20 from sfa.util.plxrn import PlXrn
21 from sfa.util.osxrn import OSXrn
22 from sfa.rspecs.version_manager import VersionManager
23 from sfa.openstack.image import ImageManager
24 from sfa.openstack.security_group import SecurityGroup
25 from sfa.util.sfalogging import logger
27 def instance_to_sliver(instance, slice_xrn=None):
29 # * instance.image_ref
30 # * instance.kernel_id
31 # * instance.ramdisk_id
32 import nova.db.sqlalchemy.models
36 if isinstance(instance, dict):
37 # this is an isntance type dict
38 name = instance['name']
39 type = instance['name']
40 elif isinstance(instance, nova.db.sqlalchemy.models.Instance):
41 # this is an object that describes a running instance
42 name = instance.display_name
43 type = instance.instance_type.name
45 raise SfaAPIError("instnace must be an instance_type dict or" + \
46 " a nova.db.sqlalchemy.models.Instance object")
48 xrn = Xrn(slice_xrn, 'slice')
49 sliver_id = xrn.get_sliver_id(instance.project_id, instance.hostname, instance.id)
51 sliver = Sliver({'slice_id': sliver_id,
58 def ec2_id(id=None, type=None):
63 ec2_id = CloudController.image_ec2_id(id, type)
69 def __init__(self, driver):
72 def get_rspec(self, slice_xrn=None, version=None, options={}):
73 version_manager = VersionManager()
74 version = version_manager.get_version(version)
76 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
77 nodes = self.get_aggregate_nodes()
79 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
80 nodes = self.get_slice_nodes(slice_xrn)
81 rspec = RSpec(version=rspec_version, user_options=options)
82 rspec.version.add_nodes(nodes)
85 def get_availability_zones(self):
86 zones = self.driver.shell.db.zone_get_all()
90 zones = [zone.name for zone in zones]
92 def get_slice_nodes(self, slice_xrn):
93 image_manager = ImageManager(self.driver)
95 zones = self.get_availability_zones()
96 name = OSXrn(xrn = slice_xrn).name
97 instances = self.driver.shell.db.instance_get_all_by_project(name)
99 for instance in instances:
102 for fixed_ip in instance.fixed_ips:
103 if_xrn = PlXrn(auth=self.driver.hrn,
104 interface='node%s:eth0' % (instance.hostname))
105 interface = Interface({'component_id': if_xrn.urn})
106 interface['ips'] = [{'address': fixed_ip['address'],
107 'netmask': fixed_ip['network'].netmask,
109 interfaces.append(interface)
110 if instance.availability_zone:
111 node_xrn = OSXrn(instance.availability_zone, 'node')
113 node_xrn = OSXrn('cloud', 'node')
115 rspec_node['component_id'] = node_xrn.urn
116 rspec_node['component_name'] = node_xrn.name
117 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
118 sliver = instance_to_sliver(instance)
119 disk_image = image_manager.get_disk_image(instance.image_ref)
120 sliver['disk_image'] = [disk_image.to_rspec_object()]
121 rspec_node['slivers'] = [sliver]
122 rspec_node['interfaces'] = interfaces
123 # slivers always provide the ssh service
124 login = Login({'authentication': 'ssh-keys',
125 'hostname': interfaces[0]['ips'][0]['address'],
126 'port':'22', 'username': 'root'})
127 service = Services({'login': login})
128 rspec_node['services'] = [service]
129 rspec_nodes.append(rspec_node)
132 def get_aggregate_nodes(self):
133 zones = self.get_availability_zones()
134 # available sliver/instance/vm types
135 instances = self.driver.shell.db.instance_type_get_all().values()
137 image_manager = ImageManager(self.driver)
138 disk_images = image_manager.get_available_disk_images()
139 disk_image_objects = [image.to_rspec_object() \
140 for image in disk_images]
144 xrn = OSXrn(zone, 'node')
145 rspec_node['component_id'] = xrn.urn
146 rspec_node['component_name'] = xrn.name
147 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
148 rspec_node['exclusive'] = 'false'
149 rspec_node['hardware_types'] = [HardwareType({'name': 'plos-pc'}),
150 HardwareType({'name': 'pc'})]
152 for instance in instances:
153 sliver = instance_to_sliver(instance)
154 sliver['disk_image'] = disk_image_objects
155 slivers.append(sliver)
157 rspec_node['slivers'] = slivers
158 rspec_nodes.append(rspec_node)
163 def create_project(self, slicename, users, options={}):
165 Create the slice if it doesn't alredy exist. Create user
166 accounts that don't already exist
168 from nova.exception import ProjectNotFound, UserNotFound
170 username = Xrn(user['urn']).get_leaf()
172 self.driver.shell.auth_manager.get_user(username)
173 except nova.exception.UserNotFound:
174 self.driver.shell.auth_manager.create_user(username)
175 self.verify_user_keys(username, user['keys'], options)
178 slice = self.driver.shell.auth_manager.get_project(slicename)
179 except ProjectNotFound:
180 # assume that the first user is the project manager
181 proj_manager = Xrn(users[0]['urn']).get_leaf()
182 self.driver.shell.auth_manager.create_project(slicename, proj_manager)
184 def verify_user_keys(self, username, keys, options={}):
188 append = options.get('append', True)
189 existing_keys = self.driver.shell.db.key_pair_get_all_by_user(username)
190 existing_pub_keys = [key.public_key for key in existing_keys]
191 removed_pub_keys = set(existing_pub_keys).difference(keys)
192 added_pub_keys = set(keys).difference(existing_pub_keys)
195 for public_key in added_pub_keys:
197 key['user_id'] = username
198 key['name'] = username
199 key['public_key'] = public_key
200 self.driver.shell.db.key_pair_create(key)
204 for key in existing_keys:
205 if key.public_key in removed_pub_keys:
206 self.driver.shell.db.key_pair_destroy(username, key.name)
209 def create_security_group(self, slicename, fw_rules=[]):
210 # use default group by default
211 group_name = 'default'
212 if isinstance(fw_rules, list) and fw_rules:
213 # Each sliver get's its own security group.
214 # Keep security group names unique by appending some random
216 random_name = "".join([random.choice(string.letters+string.digits)
218 group_name = slicename + random_name
219 security_group = SecurityGroup(self.driver)
220 security_group.create_security_group(group_name)
221 for rule in fw_rules:
222 security_group.add_rule_to_group(group_name,
223 protocol = rule.get('protocol'),
224 cidr_ip = rule.get('cidr_ip'),
225 port_range = rule.get('port_range'),
226 icmp_type_code = rule.get('icmp_type_code'))
229 def add_rule_to_security_group(self, group_name, **kwds):
230 security_group = SecurityGroup(self.driver)
231 security_group.add_rule_to_group(group_name=group_name,
232 protocol=kwds.get('protocol'),
233 cidr_ip =kwds.get('cidr_ip'),
234 icmp_type_code = kwds.get('icmp_type_code'))
237 def reserve_instance(self, image_id, kernel_id, ramdisk_id, \
238 instance_type, key_name, user_data, group_name):
239 conn = self.driver.euca_shell.get_euca_connection()
240 logger.info('Reserving an instance: image: %s, kernel: ' \
241 '%s, ramdisk: %s, type: %s, key: %s' % \
242 (image_id, kernel_id, ramdisk_id,
243 instance_type, key_name))
245 reservation = conn.run_instances(image_id=image_id,
247 ramdisk_id=ramdisk_id,
248 instance_type=instance_type,
250 user_data = user_data,
251 security_groups=[group_name])
253 #min_count=min_count,
254 #max_count=max_count,
256 except Exception, err:
260 def run_instances(self, slicename, rspec, keyname, pubkeys):
262 Create the security groups and instances.
264 # the default image to use for instnaces that dont
265 # explicitly request an image.
266 # Just choose the first available image for now.
267 image_manager = ImageManager(self.driver)
268 available_images = image_manager.get_available_disk_images()
269 default_image_id = None
270 default_aki_id = None
271 default_ari_id = None
272 default_image = available_images[0]
273 default_image_id = ec2_id(default_image.id, default_image.container_format)
274 default_aki_id = ec2_id(default_image.kernel_id, 'aki')
275 default_ari_id = ec2_id(default_image.ramdisk_id, 'ari')
277 # get requested slivers
279 user_data = "\n".join(pubkeys)
280 requested_instances = defaultdict(list)
281 # iterate over clouds/zones/nodes
282 for node in rspec.version.get_nodes_with_slivers():
283 instance_types = node.get('slivers', [])
284 if isinstance(instance_types, list):
285 # iterate over sliver/instance types
286 for instance_type in instance_types:
287 fw_rules = instance_type.get('fw_rules', [])
288 group_name = self.create_security_group(slicename, fw_rules)
289 ami_id = default_image_id
290 aki_id = default_aki_id
291 ari_id = default_ari_id
292 req_image = instance_type.get('disk_image')
293 if req_image and isinstance(req_image, list):
294 req_image_name = req_image[0]['name']
295 disk_image = image_manager.get_disk_image(name=req_image_name)
297 ami_id = ec2_id(disk_image.id, disk_image.container_format)
298 aki_id = ec2_id(disk_image.kernel_id, 'aki')
299 ari_id = ec2_id(disk_image.ramdisk_id, 'ari')
301 self.reserve_instance(image_id=ami_id,
304 instance_type=instance_type['name'],
307 group_name=group_name)
310 def delete_instances(self, project_name):
311 instances = self.driver.shell.db.instance_get_all_by_project(project_name)
312 security_group_manager = SecurityGroup(self.driver)
313 for instance in instances:
314 # deleate this instance's security groups
315 for security_group in instance.security_groups:
316 # dont delete the default security group
317 if security_group.name != 'default':
318 security_group_manager.delete_security_group(security_group.name)
320 self.driver.shell.db.instance_destroy(instance.id)
323 def stop_instances(self, project_name):
324 instances = self.driver.shell.db.instance_get_all_by_project(project_name)
325 for instance in instances:
326 self.driver.shell.db.instance_stop(instance.id)
329 def update_instances(self, project_name):