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 rspec_nodes.append(rspec_node)
126 def get_aggregate_nodes(self):
127 zones = self.get_availability_zones()
128 # available sliver/instance/vm types
129 instances = self.driver.shell.db.instance_type_get_all().values()
131 image_manager = ImageManager(self.driver)
132 disk_images = image_manager.get_available_disk_images()
133 disk_image_objects = [image.to_rspec_object() \
134 for image in disk_images]
138 xrn = OSXrn(zone, 'node')
139 rspec_node['component_id'] = xrn.urn
140 rspec_node['component_name'] = xrn.name
141 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
142 rspec_node['exclusive'] = 'false'
143 rspec_node['hardware_types'] = [HardwareType({'name': 'plos-pc'}),
144 HardwareType({'name': 'pc'})]
146 for instance in instances:
147 sliver = instance_to_sliver(instance)
148 sliver['disk_image'] = disk_image_objects
149 slivers.append(sliver)
151 rspec_node['slivers'] = slivers
152 rspec_nodes.append(rspec_node)
157 def create_project(self, slicename, users, options={}):
159 Create the slice if it doesn't alredy exist. Create user
160 accounts that don't already exist
162 from nova.exception import ProjectNotFound, UserNotFound
164 username = Xrn(user['urn']).get_leaf()
166 self.driver.shell.auth_manager.get_user(username)
167 except nova.exception.UserNotFound:
168 self.driver.shell.auth_manager.create_user(username)
169 self.verify_user_keys(username, user['keys'], options)
172 slice = self.driver.shell.auth_manager.get_project(slicename)
173 except ProjectNotFound:
174 # assume that the first user is the project manager
175 proj_manager = Xrn(users[0]['urn']).get_leaf()
176 self.driver.shell.auth_manager.create_project(slicename, proj_manager)
178 def verify_user_keys(self, username, keys, options={}):
182 append = options.get('append', True)
183 existing_keys = self.driver.shell.db.key_pair_get_all_by_user(username)
184 existing_pub_keys = [key.public_key for key in existing_keys]
185 removed_pub_keys = set(existing_pub_keys).difference(keys)
186 added_pub_keys = set(keys).difference(existing_pub_keys)
189 for public_key in added_pub_keys:
191 key['user_id'] = username
192 key['name'] = username
193 key['public_key'] = public_key
194 self.driver.shell.db.key_pair_create(key)
198 for key in existing_keys:
199 if key.public_key in removed_pub_keys:
200 self.driver.shell.db.key_pair_destroy(username, key.name)
203 def create_security_group(self, slicename, fw_rules=[]):
204 # use default group by default
205 group_name = 'default'
206 if isinstance(fw_rules, list) and fw_rules:
207 # Each sliver get's its own security group.
208 # Keep security group names unique by appending some random
210 random_name = "".join([random.choice(string.letters+string.digits)
212 group_name = slicename + random_name
213 security_group = SecurityGroup(self.driver)
214 security_group.create_security_group(group_name)
215 for rule in fw_rules:
216 security_group.add_rule_to_group(group_name,
217 protocol = rule.get('protocol'),
218 cidr_ip = rule.get('cidr_ip'),
219 port_range = rule.get('port_range'),
220 icmp_type_code = rule.get('icmp_type_code'))
223 def add_rule_to_security_group(self, group_name, **kwds):
224 security_group = SecurityGroup(self.driver)
225 security_group.add_rule_to_group(group_name=group_name,
226 protocol=kwds.get('protocol'),
227 cidr_ip =kwds.get('cidr_ip'),
228 icmp_type_code = kwds.get('icmp_type_code'))
231 def reserve_instance(self, image_id, kernel_id, ramdisk_id, \
232 instance_type, key_name, user_data, group_name):
233 conn = self.driver.euca_shell.get_euca_connection()
234 logger.info('Reserving an instance: image: %s, kernel: ' \
235 '%s, ramdisk: %s, type: %s, key: %s' % \
236 (image_id, kernel_id, ramdisk_id,
237 instance_type, key_name))
239 reservation = conn.run_instances(image_id=image_id,
241 ramdisk_id=ramdisk_id,
242 instance_type=instance_type,
244 user_data = user_data,
245 security_groups=[group_name])
247 #min_count=min_count,
248 #max_count=max_count,
250 except Exception, err:
254 def run_instances(self, slicename, rspec, keyname, pubkeys):
256 Create the security groups and instances.
258 # the default image to use for instnaces that dont
259 # explicitly request an image.
260 # Just choose the first available image for now.
261 image_manager = ImageManager(self.driver)
262 available_images = image_manager.get_available_disk_images()
263 default_image_id = None
264 default_aki_id = None
265 default_ari_id = None
266 default_image = available_images[0]
267 default_image_id = ec2_id(default_image.id, default_image.container_format)
268 default_aki_id = ec2_id(default_image.kernel_id, 'aki')
269 default_ari_id = ec2_id(default_image.ramdisk_id, 'ari')
271 # get requested slivers
273 user_data = "\n".join(pubkeys)
274 requested_instances = defaultdict(list)
275 # iterate over clouds/zones/nodes
276 for node in rspec.version.get_nodes_with_slivers():
277 instance_types = node.get('slivers', [])
278 if isinstance(instance_types, list):
279 # iterate over sliver/instance types
280 for instance_type in instance_types:
281 fw_rules = instance_type.get('fw_rules', [])
282 group_name = self.create_security_group(slicename, fw_rules)
283 ami_id = default_image_id
284 aki_id = default_aki_id
285 ari_id = default_ari_id
286 req_image = instance_type.get('disk_image')
287 if req_image and isinstance(req_image, list):
288 req_image_name = req_image[0]['name']
289 disk_image = image_manager.get_disk_image(name=req_image_name)
291 ami_id = ec2_id(disk_image.id, disk_image.container_format)
292 aki_id = ec2_id(disk_image.kernel_id, 'aki')
293 ari_id = ec2_id(disk_image.ramdisk_id, 'ari')
295 self.reserve_instance(image_id=ami_id,
298 instance_type=instance_type['name'],
301 group_name=group_name)
304 def delete_instances(self, project_name):
305 instances = self.driver.shell.db.instance_get_all_by_project(project_name)
306 security_group_manager = SecurityGroup(self.driver)
307 for instance in instances:
308 # deleate this instance's security groups
309 for security_group in instance.security_groups:
310 # dont delete the default security group
311 if security_group.name != 'default':
312 security_group_manager.delete_security_group(security_group.name)
314 self.driver.shell.db.instance_destroy(instance.id)
317 def stop_instances(self, project_name):
318 instances = self.driver.shell.db.instance_get_all_by_project(project_name)
319 for instance in instances:
320 self.driver.shell.db.instance_stop(instance.id)
323 def update_instances(self, project_name):