services.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. """
  2. Services implemented by the AWS provider.
  3. """
  4. import string
  5. from boto.ec2.blockdevicemapping import BlockDeviceMapping
  6. from boto.ec2.blockdevicemapping import BlockDeviceType
  7. from boto.exception import EC2ResponseError
  8. from cloudbridge.cloud.base.resources import BaseLaunchConfig
  9. from cloudbridge.cloud.base.resources import ClientPagedResultList
  10. from cloudbridge.cloud.base.resources import ServerPagedResultList
  11. from cloudbridge.cloud.base.services import BaseBlockStoreService
  12. from cloudbridge.cloud.base.services import BaseComputeService
  13. from cloudbridge.cloud.base.services import BaseImageService
  14. from cloudbridge.cloud.base.services import BaseInstanceService
  15. from cloudbridge.cloud.base.services import BaseInstanceTypesService
  16. from cloudbridge.cloud.base.services import BaseKeyPairService
  17. from cloudbridge.cloud.base.services import BaseNetworkService
  18. from cloudbridge.cloud.base.services import BaseObjectStoreService
  19. from cloudbridge.cloud.base.services import BaseRegionService
  20. from cloudbridge.cloud.base.services import BaseSecurityGroupService
  21. from cloudbridge.cloud.base.services import BaseSecurityService
  22. from cloudbridge.cloud.base.services import BaseSnapshotService
  23. from cloudbridge.cloud.base.services import BaseSubnetService
  24. from cloudbridge.cloud.base.services import BaseVolumeService
  25. from cloudbridge.cloud.interfaces.resources import InstanceType
  26. from cloudbridge.cloud.interfaces.resources \
  27. import InvalidConfigurationException
  28. from cloudbridge.cloud.interfaces.resources import KeyPair
  29. from cloudbridge.cloud.interfaces.resources import MachineImage
  30. # from cloudbridge.cloud.interfaces.resources import Network
  31. from cloudbridge.cloud.interfaces.resources import PlacementZone
  32. from cloudbridge.cloud.interfaces.resources import SecurityGroup
  33. from cloudbridge.cloud.interfaces.resources import Snapshot
  34. from cloudbridge.cloud.interfaces.resources import Volume
  35. import requests
  36. from .resources import AWSBucket
  37. from .resources import AWSFloatingIP
  38. from .resources import AWSInstance
  39. from .resources import AWSInstanceType
  40. from .resources import AWSKeyPair
  41. from .resources import AWSMachineImage
  42. from .resources import AWSNetwork
  43. from .resources import AWSRegion
  44. from .resources import AWSSecurityGroup
  45. from .resources import AWSSnapshot
  46. from .resources import AWSSubnet
  47. from .resources import AWSVolume
  48. class AWSSecurityService(BaseSecurityService):
  49. def __init__(self, provider):
  50. super(AWSSecurityService, self).__init__(provider)
  51. # Initialize provider services
  52. self._key_pairs = AWSKeyPairService(provider)
  53. self._security_groups = AWSSecurityGroupService(provider)
  54. @property
  55. def key_pairs(self):
  56. """
  57. Provides access to key pairs for this provider.
  58. :rtype: ``object`` of :class:`.KeyPairService`
  59. :return: a KeyPairService object
  60. """
  61. return self._key_pairs
  62. @property
  63. def security_groups(self):
  64. """
  65. Provides access to security groups for this provider.
  66. :rtype: ``object`` of :class:`.SecurityGroupService`
  67. :return: a SecurityGroupService object
  68. """
  69. return self._security_groups
  70. class AWSKeyPairService(BaseKeyPairService):
  71. def __init__(self, provider):
  72. super(AWSKeyPairService, self).__init__(provider)
  73. def get(self, key_pair_id):
  74. """
  75. Returns a KeyPair given its ID.
  76. """
  77. try:
  78. kps = self.provider.ec2_conn.get_all_key_pairs(
  79. keynames=[key_pair_id])
  80. return AWSKeyPair(self.provider, kps[0])
  81. except EC2ResponseError:
  82. return None
  83. def list(self, limit=None, marker=None):
  84. """
  85. List all key pairs associated with this account.
  86. :rtype: ``list`` of :class:`.KeyPair`
  87. :return: list of KeyPair objects
  88. """
  89. key_pairs = [AWSKeyPair(self.provider, kp)
  90. for kp in self.provider.ec2_conn.get_all_key_pairs()]
  91. return ClientPagedResultList(self.provider, key_pairs,
  92. limit=limit, marker=marker)
  93. def find(self, name, limit=None, marker=None):
  94. """
  95. Searches for a key pair by a given list of attributes.
  96. """
  97. try:
  98. key_pairs = [
  99. AWSKeyPair(self.provider, kp) for kp in
  100. self.provider.ec2_conn.get_all_key_pairs(keynames=[name])]
  101. except EC2ResponseError:
  102. key_pairs = []
  103. return ClientPagedResultList(self.provider, key_pairs,
  104. limit=limit, marker=marker)
  105. def create(self, name):
  106. """
  107. Create a new key pair or raise an exception if one already exists.
  108. :type name: str
  109. :param name: The name of the key pair to be created.
  110. :rtype: ``object`` of :class:`.KeyPair`
  111. :return: A key pair instance or ``None`` if one was not be created.
  112. """
  113. kp = self.provider.ec2_conn.create_key_pair(name)
  114. if kp:
  115. return AWSKeyPair(self.provider, kp)
  116. return None
  117. class AWSSecurityGroupService(BaseSecurityGroupService):
  118. def __init__(self, provider):
  119. super(AWSSecurityGroupService, self).__init__(provider)
  120. def get(self, sg_id):
  121. """
  122. Returns a SecurityGroup given its id.
  123. """
  124. try:
  125. sgs = self.provider.ec2_conn.get_all_security_groups(
  126. group_ids=[sg_id])
  127. return AWSSecurityGroup(self.provider, sgs[0]) if sgs else None
  128. except EC2ResponseError:
  129. return None
  130. def list(self, limit=None, marker=None):
  131. """
  132. List all security groups associated with this account.
  133. :rtype: ``list`` of :class:`.SecurityGroup`
  134. :return: list of SecurityGroup objects
  135. """
  136. sgs = [AWSSecurityGroup(self.provider, sg)
  137. for sg in self.provider.ec2_conn.get_all_security_groups()]
  138. return ClientPagedResultList(self.provider, sgs,
  139. limit=limit, marker=marker)
  140. def create(self, name, description, network_id=None):
  141. """
  142. Create a new SecurityGroup.
  143. :type name: str
  144. :param name: The name of the new security group.
  145. :type description: str
  146. :param description: The description of the new security group.
  147. :type network_id: ``str``
  148. :param network_id: The ID of the VPC to create the security group in,
  149. if any.
  150. :rtype: ``object`` of :class:`.SecurityGroup`
  151. :return: A SecurityGroup instance or ``None`` if one was not created.
  152. """
  153. sg = self.provider.ec2_conn.create_security_group(name, description,
  154. network_id)
  155. if sg:
  156. return AWSSecurityGroup(self.provider, sg)
  157. return None
  158. def find(self, name, limit=None, marker=None):
  159. """
  160. Get all security groups associated with your account.
  161. """
  162. try:
  163. flters = {'group-name': name}
  164. security_groups = self.provider.ec2_conn.get_all_security_groups(
  165. filters=flters)
  166. except EC2ResponseError:
  167. security_groups = []
  168. return [AWSSecurityGroup(self.provider, sg) for sg in security_groups]
  169. def delete(self, group_id):
  170. """
  171. Delete an existing SecurityGroup.
  172. :type group_id: str
  173. :param group_id: The security group ID to be deleted.
  174. :rtype: ``bool``
  175. :return: ``True`` if the security group does not exist, ``False``
  176. otherwise. Note that this implies that the group may not have
  177. been deleted by this method but instead has not existed in
  178. the first place.
  179. """
  180. try:
  181. for sg in self.provider.ec2_conn.get_all_security_groups(
  182. group_ids=[group_id]):
  183. try:
  184. sg.delete()
  185. except EC2ResponseError:
  186. return False
  187. except EC2ResponseError:
  188. pass
  189. return True
  190. class AWSBlockStoreService(BaseBlockStoreService):
  191. def __init__(self, provider):
  192. super(AWSBlockStoreService, self).__init__(provider)
  193. # Initialize provider services
  194. self._volume_svc = AWSVolumeService(self.provider)
  195. self._snapshot_svc = AWSSnapshotService(self.provider)
  196. @property
  197. def volumes(self):
  198. return self._volume_svc
  199. @property
  200. def snapshots(self):
  201. return self._snapshot_svc
  202. class AWSVolumeService(BaseVolumeService):
  203. def __init__(self, provider):
  204. super(AWSVolumeService, self).__init__(provider)
  205. def get(self, volume_id):
  206. """
  207. Returns a volume given its id.
  208. """
  209. vols = self.provider.ec2_conn.get_all_volumes(volume_ids=[volume_id])
  210. return AWSVolume(self.provider, vols[0]) if vols else None
  211. def find(self, name, limit=None, marker=None):
  212. """
  213. Searches for a volume by a given list of attributes.
  214. """
  215. filtr = {'tag:Name': name}
  216. aws_vols = self.provider.ec2_conn.get_all_volumes(filters=filtr)
  217. cb_vols = [AWSVolume(self.provider, vol) for vol in aws_vols]
  218. return ClientPagedResultList(self.provider, cb_vols,
  219. limit=limit, marker=marker)
  220. def list(self, limit=None, marker=None):
  221. """
  222. List all volumes.
  223. """
  224. aws_vols = self.provider.ec2_conn.get_all_volumes()
  225. cb_vols = [AWSVolume(self.provider, vol) for vol in aws_vols]
  226. return ClientPagedResultList(self.provider, cb_vols,
  227. limit=limit, marker=marker)
  228. def create(self, name, size, zone, snapshot=None, description=None):
  229. """
  230. Creates a new volume.
  231. """
  232. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  233. snapshot_id = snapshot.id if isinstance(
  234. snapshot, AWSSnapshot) and snapshot else snapshot
  235. ec2_vol = self.provider.ec2_conn.create_volume(
  236. size,
  237. zone_id,
  238. snapshot=snapshot_id)
  239. cb_vol = AWSVolume(self.provider, ec2_vol)
  240. cb_vol.name = name
  241. if description:
  242. cb_vol.description = description
  243. return cb_vol
  244. class AWSSnapshotService(BaseSnapshotService):
  245. def __init__(self, provider):
  246. super(AWSSnapshotService, self).__init__(provider)
  247. def get(self, snapshot_id):
  248. """
  249. Returns a snapshot given its id.
  250. """
  251. try:
  252. snaps = self.provider.ec2_conn.get_all_snapshots(
  253. snapshot_ids=[snapshot_id])
  254. except EC2ResponseError as ec2e:
  255. if ec2e.code == 'InvalidSnapshot.NotFound':
  256. return None
  257. raise ec2e
  258. return AWSSnapshot(self.provider, snaps[0]) if snaps else None
  259. def find(self, name, limit=None, marker=None):
  260. """
  261. Searches for a snapshot by a given list of attributes.
  262. """
  263. filtr = {'tag-value': name}
  264. snaps = [AWSSnapshot(self.provider, snap) for snap in
  265. self.provider.ec2_conn.get_all_snapshots(filters=filtr)]
  266. return ClientPagedResultList(self.provider, snaps,
  267. limit=limit, marker=marker)
  268. def list(self, limit=None, marker=None):
  269. """
  270. List all snapshots.
  271. """
  272. snaps = [AWSSnapshot(self.provider, snap)
  273. for snap in self.provider.ec2_conn.get_all_snapshots(
  274. owner='self')]
  275. return ClientPagedResultList(self.provider, snaps,
  276. limit=limit, marker=marker)
  277. def create(self, name, volume, description=None):
  278. """
  279. Creates a new snapshot of a given volume.
  280. """
  281. volume_id = volume.id if isinstance(volume, AWSVolume) else volume
  282. ec2_snap = self.provider.ec2_conn.create_snapshot(
  283. volume_id,
  284. description=description)
  285. cb_snap = AWSSnapshot(self.provider, ec2_snap)
  286. cb_snap.name = name
  287. if description:
  288. cb_snap.description = description
  289. return cb_snap
  290. class AWSObjectStoreService(BaseObjectStoreService):
  291. def __init__(self, provider):
  292. super(AWSObjectStoreService, self).__init__(provider)
  293. def get(self, bucket_id):
  294. """
  295. Returns a bucket given its ID. Returns ``None`` if the bucket
  296. does not exist.
  297. """
  298. bucket = self.provider.s3_conn.lookup(bucket_id)
  299. if bucket:
  300. return AWSBucket(self.provider, bucket)
  301. else:
  302. return None
  303. def find(self, name, limit=None, marker=None):
  304. """
  305. Searches for a bucket by a given list of attributes.
  306. """
  307. buckets = [AWSBucket(self.provider, bucket)
  308. for bucket in self.provider.s3_conn.get_all_buckets()
  309. if name in bucket.name]
  310. return ClientPagedResultList(self.provider, buckets,
  311. limit=limit, marker=marker)
  312. def list(self, limit=None, marker=None):
  313. """
  314. List all containers.
  315. """
  316. buckets = [AWSBucket(self.provider, bucket)
  317. for bucket in self.provider.s3_conn.get_all_buckets()]
  318. return ClientPagedResultList(self.provider, buckets,
  319. limit=limit, marker=marker)
  320. def create(self, name, location=None):
  321. """
  322. Create a new bucket.
  323. """
  324. bucket = self.provider.s3_conn.create_bucket(
  325. name,
  326. location=location if location else '')
  327. return AWSBucket(self.provider, bucket)
  328. class AWSImageService(BaseImageService):
  329. def __init__(self, provider):
  330. super(AWSImageService, self).__init__(provider)
  331. def get(self, image_id):
  332. """
  333. Returns an Image given its id
  334. """
  335. try:
  336. image = self.provider.ec2_conn.get_image(image_id)
  337. if image:
  338. return AWSMachineImage(self.provider, image)
  339. except EC2ResponseError:
  340. pass
  341. return None
  342. def find(self, name, limit=None, marker=None):
  343. """
  344. Searches for an image by a given list of attributes
  345. """
  346. filters = {'name': name}
  347. images = [AWSMachineImage(self.provider, image) for image in
  348. self.provider.ec2_conn.get_all_images(filters=filters)]
  349. return ClientPagedResultList(self.provider, images,
  350. limit=limit, marker=marker)
  351. def list(self, limit=None, marker=None):
  352. """
  353. List all images.
  354. """
  355. images = [AWSMachineImage(self.provider, image)
  356. for image in self.provider.ec2_conn.get_all_images()]
  357. return ClientPagedResultList(self.provider, images,
  358. limit=limit, marker=marker)
  359. class AWSComputeService(BaseComputeService):
  360. def __init__(self, provider):
  361. super(AWSComputeService, self).__init__(provider)
  362. self._instance_type_svc = AWSInstanceTypesService(self.provider)
  363. self._instance_svc = AWSInstanceService(self.provider)
  364. self._region_svc = AWSRegionService(self.provider)
  365. self._images_svc = AWSImageService(self.provider)
  366. @property
  367. def images(self):
  368. return self._images_svc
  369. @property
  370. def instance_types(self):
  371. return self._instance_type_svc
  372. @property
  373. def instances(self):
  374. return self._instance_svc
  375. @property
  376. def regions(self):
  377. return self._region_svc
  378. class AWSInstanceService(BaseInstanceService):
  379. def __init__(self, provider):
  380. super(AWSInstanceService, self).__init__(provider)
  381. def create(self, name, image, instance_type, zone=None,
  382. key_pair=None, security_groups=None, user_data=None,
  383. launch_config=None,
  384. **kwargs):
  385. """
  386. Creates a new virtual machine instance.
  387. If no VPC/subnet was specified (via ``launch_config`` parameter), this
  388. method will search for a default VPC and attempt to launch an instance
  389. into that VPC.
  390. """
  391. image_id = image.id if isinstance(image, MachineImage) else image
  392. instance_size = instance_type.id if \
  393. isinstance(instance_type, InstanceType) else instance_type
  394. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  395. key_pair_name = key_pair.name if isinstance(
  396. key_pair,
  397. KeyPair) else key_pair
  398. if launch_config:
  399. bdm = self._process_block_device_mappings(launch_config, zone_id)
  400. subnet_id = self._get_net_id(launch_config)
  401. else:
  402. bdm = subnet_id = None
  403. subnet_id, zone_id, security_group_ids = \
  404. self._resolve_launch_options(subnet_id, zone_id, security_groups)
  405. reservation = self.provider.ec2_conn.run_instances(
  406. image_id=image_id, instance_type=instance_size,
  407. min_count=1, max_count=1, placement=zone_id,
  408. key_name=key_pair_name, security_group_ids=security_group_ids,
  409. user_data=user_data, block_device_map=bdm, subnet_id=subnet_id)
  410. if reservation:
  411. instance = AWSInstance(self.provider, reservation.instances[0])
  412. instance.name = name
  413. return instance
  414. def _resolve_launch_options(self, subnet_id, zone_id, security_groups):
  415. """
  416. Resolve inter-dependent launch options.
  417. With launching into VPC only, try to figure out a default
  418. VPC to launch into, making placement decisions along the way that
  419. are implied from the zone a subnet exists in.
  420. """
  421. def _deduce_subnet_and_zone(vpc, zone_id=None):
  422. """
  423. Figure out subnet ID from a VPC (and zone_id, if not supplied).
  424. """
  425. if zone_id:
  426. # A placement zone was specified. Choose the default
  427. # subnet in that zone.
  428. for sn in vpc.subnets():
  429. if sn._subnet.availability_zone == zone_id:
  430. subnet_id = sn.id
  431. else:
  432. # No zone was requested, so just pick one subnet
  433. sn = vpc.subnets()[0]
  434. subnet_id = sn.id
  435. zone_id = sn._subnet.availability_zone
  436. return subnet_id, zone_id
  437. vpc_id = None
  438. sg_ids = []
  439. if subnet_id:
  440. # Subnet was supplied - get the VPC so named SGs can be resolved
  441. subnet = self.provider.vpc_conn.get_all_subnets(subnet_id)[0]
  442. vpc_id = subnet.vpc_id
  443. # zone_id must match zone where the requested subnet lives
  444. if zone_id and subnet.availability_zone != zone_id:
  445. raise ValueError("Requested placement zone ({0}) must match "
  446. "specified subnet's availability zone ({1})."
  447. .format(zone_id, subnet.availability_zone))
  448. if security_groups:
  449. # Try to get a subnet via specified SGs. This will work only if
  450. # the specified SGs are within a VPC (which is a prerequisite to
  451. # launch into VPC anyhow).
  452. sg_ids = self._process_security_groups(security_groups, vpc_id)
  453. # Must iterate through all the SGs here because a SG name may
  454. # exist in a VPC or EC2-Classic so opt for the VPC SG. This
  455. # applies in the case no subnet was specified.
  456. if not subnet_id:
  457. for sg_id in sg_ids:
  458. sg = self.provider.security.security_groups.get(sg_id)
  459. if sg._security_group.vpc_id:
  460. if sg_ids and sg_id not in sg_ids:
  461. raise ValueError("Multiple matches for VPC "
  462. "security group(s) {0}."
  463. .format(security_groups))
  464. else:
  465. sg_ids.append(sg_id)
  466. vpc = self.provider.network.get(
  467. sg._security_group.vpc_id)
  468. subnet_id, zone_id = _deduce_subnet_and_zone(
  469. vpc, zone_id)
  470. else:
  471. sg_ids = sg_ids
  472. if not subnet_id:
  473. raise AttributeError("Supplied security group(s) ({0}) must "
  474. "be associated with a VPC."
  475. .format(security_groups))
  476. if not subnet_id and not security_groups:
  477. # No VPC/subnet was supplied, search for the default VPC.
  478. for vpc in self.provider.network.list():
  479. if vpc._vpc.is_default:
  480. vpc_id = vpc.id
  481. subnet_id, zone_id = _deduce_subnet_and_zone(vpc, zone_id)
  482. else:
  483. raise AttributeError("No default VPC exists. Supply a "
  484. "subnet to launch into (via "
  485. "launch_config param).")
  486. return subnet_id, zone_id, sg_ids
  487. def _process_security_groups(self, security_groups, vpc_id=None):
  488. """
  489. Process security groups to create a list of SG ID's for launching.
  490. :type security_groups: A ``list`` of ``SecurityGroup`` objects or a
  491. list of ``str`` names
  492. :param security_groups: A list of ``SecurityGroup`` objects or a list
  493. of ``SecurityGroup`` names, which should be
  494. assigned to this instance.
  495. :type vpc_id: ``str``
  496. :param vpc_id: A VPC ID within which the supplied security groups exist
  497. :rtype: ``list``
  498. :return: A list of security group IDs.
  499. """
  500. if isinstance(security_groups, list) and \
  501. isinstance(security_groups[0], SecurityGroup):
  502. sg_ids = [sg.id for sg in security_groups]
  503. else:
  504. # SG names were supplied, need to map them to SG IDs.
  505. sg_ids = []
  506. # If a VPC was specified, need to map to the SGs in the VPC.
  507. flters = None
  508. if vpc_id:
  509. flters = {'vpc_id': vpc_id}
  510. sgs = self.provider.ec2_conn.get_all_security_groups(
  511. filters=flters)
  512. sg_ids = [sg.id for sg in sgs if sg.name in security_groups]
  513. return sg_ids
  514. def _process_block_device_mappings(self, launch_config, zone=None):
  515. """
  516. Processes block device mapping information
  517. and returns a Boto BlockDeviceMapping object. If new volumes
  518. are requested (source is None and destination is VOLUME), they will be
  519. created and the relevant volume ids included in the mapping.
  520. """
  521. bdm = BlockDeviceMapping()
  522. # Assign letters from f onwards
  523. # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html
  524. next_letter = iter(list(string.ascii_lowercase[6:]))
  525. # assign ephemeral devices from 0 onwards
  526. ephemeral_counter = 0
  527. for device in launch_config.block_devices:
  528. bd_type = BlockDeviceType()
  529. if device.is_volume:
  530. if device.is_root:
  531. bdm['/dev/sda1'] = bd_type
  532. else:
  533. bdm['sd' + next(next_letter)] = bd_type
  534. if isinstance(device.source, Snapshot):
  535. bd_type.snapshot_id = device.source.id
  536. elif isinstance(device.source, Volume):
  537. bd_type.volume_id = device.source.id
  538. elif isinstance(device.source, MachineImage):
  539. # Not supported
  540. pass
  541. else:
  542. # source is None, but destination is volume, therefore
  543. # create a blank volume. If the Zone is None, this
  544. # could fail since the volume and instance may be created
  545. # in two different zones.
  546. if not zone:
  547. raise InvalidConfigurationException(
  548. "A zone must be specified when launching with a"
  549. " new blank volume block device mapping.")
  550. new_vol = self.provider.block_store.volumes.create(
  551. '',
  552. device.size,
  553. zone)
  554. bd_type.volume_id = new_vol.id
  555. bd_type.delete_on_terminate = device.delete_on_terminate
  556. if device.size:
  557. bd_type.size = device.size
  558. else: # device is ephemeral
  559. bd_type.ephemeral_name = 'ephemeral%s' % ephemeral_counter
  560. return bdm
  561. def _get_net_id(self, launch_config):
  562. return (launch_config.network_interfaces[0]
  563. if len(launch_config.network_interfaces) > 0
  564. else None)
  565. def create_launch_config(self):
  566. return BaseLaunchConfig(self.provider)
  567. def get(self, instance_id):
  568. """
  569. Returns an instance given its id. Returns None
  570. if the object does not exist.
  571. """
  572. reservation = self.provider.ec2_conn.get_all_reservations(
  573. instance_ids=[instance_id])
  574. if reservation:
  575. return AWSInstance(self.provider, reservation[0].instances[0])
  576. else:
  577. return None
  578. def find(self, name, limit=None, marker=None):
  579. """
  580. Searches for an instance by a given list of attributes.
  581. :rtype: ``object`` of :class:`.Instance`
  582. :return: an Instance object
  583. """
  584. filtr = {'tag:Name': name}
  585. reservations = self.provider.ec2_conn.get_all_reservations(
  586. filters=filtr,
  587. max_results=limit,
  588. next_token=marker)
  589. instances = [AWSInstance(self.provider, inst)
  590. for res in reservations
  591. for inst in res.instances]
  592. return ServerPagedResultList(reservations.is_truncated,
  593. reservations.next_token,
  594. False, data=instances)
  595. def list(self, limit=None, marker=None):
  596. """
  597. List all instances.
  598. """
  599. reservations = self.provider.ec2_conn.get_all_reservations(
  600. max_results=limit,
  601. next_token=marker)
  602. instances = [AWSInstance(self.provider, inst)
  603. for res in reservations
  604. for inst in res.instances]
  605. return ServerPagedResultList(reservations.is_truncated,
  606. reservations.next_token,
  607. False, data=instances)
  608. AWS_INSTANCE_DATA_DEFAULT_URL = "https://d168wakzal7fp0.cloudfront.net/" \
  609. "aws_instance_data.json"
  610. class AWSInstanceTypesService(BaseInstanceTypesService):
  611. def __init__(self, provider):
  612. super(AWSInstanceTypesService, self).__init__(provider)
  613. @property
  614. def instance_data(self):
  615. """
  616. TODO: Needs a caching function with timeout
  617. """
  618. r = requests.get(self.provider.config.get(
  619. "aws_instance_info_url", AWS_INSTANCE_DATA_DEFAULT_URL))
  620. return r.json()
  621. def list(self, limit=None, marker=None):
  622. inst_types = [AWSInstanceType(self.provider, inst_type)
  623. for inst_type in self.instance_data]
  624. return ClientPagedResultList(self.provider, inst_types,
  625. limit=limit, marker=marker)
  626. class AWSRegionService(BaseRegionService):
  627. def __init__(self, provider):
  628. super(AWSRegionService, self).__init__(provider)
  629. def get(self, region_id):
  630. region = self.provider.ec2_conn.get_all_regions(
  631. region_names=[region_id])
  632. if region:
  633. return AWSRegion(self.provider, region[0])
  634. else:
  635. return None
  636. def list(self, limit=None, marker=None):
  637. regions = [AWSRegion(self.provider, region)
  638. for region in self.provider.ec2_conn.get_all_regions()]
  639. return ClientPagedResultList(self.provider, regions,
  640. limit=limit, marker=marker)
  641. @property
  642. def current(self):
  643. return self.get(self._provider.region_name)
  644. class AWSNetworkService(BaseNetworkService):
  645. def __init__(self, provider):
  646. super(AWSNetworkService, self).__init__(provider)
  647. self._subnet_svc = AWSSubnetService(self.provider)
  648. def get(self, network_id):
  649. network = self.provider.vpc_conn.get_all_vpcs(vpc_ids=[network_id])
  650. if network:
  651. return AWSNetwork(self.provider, network[0])
  652. return None
  653. def list(self, limit=None, marker=None):
  654. networks = [AWSNetwork(self.provider, network)
  655. for network in self.provider.vpc_conn.get_all_vpcs()]
  656. return ClientPagedResultList(self.provider, networks,
  657. limit=limit, marker=marker)
  658. def create(self, name=None):
  659. # AWS requried CIDR block to be specified when creating a network
  660. # so set a default one and use the largest possible netmask.
  661. default_cidr = '10.0.0.0/16'
  662. network = self.provider.vpc_conn.create_vpc(cidr_block=default_cidr)
  663. cb_network = AWSNetwork(self.provider, network)
  664. if name:
  665. cb_network.name = name
  666. return cb_network
  667. @property
  668. def subnets(self):
  669. return self._subnet_svc
  670. def floating_ips(self, network_id=None):
  671. fltrs = None
  672. if network_id:
  673. fltrs = {'network-interface-id': network_id}
  674. al = self.provider.vpc_conn.get_all_addresses(filters=fltrs)
  675. return [AWSFloatingIP(self.provider, a) for a in al]
  676. def create_floating_ip(self):
  677. ip = self.provider.ec2_conn.allocate_address(domain='vpc')
  678. return AWSFloatingIP(self.provider, ip)
  679. class AWSSubnetService(BaseSubnetService):
  680. def __init__(self, provider):
  681. super(AWSSubnetService, self).__init__(provider)
  682. def get(self, subnet_id):
  683. subnets = self.provider.vpc_conn.get_all_subnets([subnet_id])
  684. if subnets:
  685. return AWSSubnet(self.provider, subnets[0])
  686. return None
  687. def list(self, network=None):
  688. fltr = None
  689. if network:
  690. network_id = (network.id if isinstance(network, AWSNetwork) else
  691. network)
  692. fltr = {'vpc-id': network_id}
  693. subnets = self.provider.vpc_conn.get_all_subnets(filters=fltr)
  694. return [AWSSubnet(self.provider, subnet) for subnet in subnets]
  695. def create(self, network, cidr_block, name=None):
  696. network_id = network.id if isinstance(network, AWSNetwork) else network
  697. subnet = self.provider.vpc_conn.create_subnet(network_id, cidr_block)
  698. cb_subnet = AWSSubnet(self.provider, subnet)
  699. if name:
  700. cb_subnet.name = name
  701. return cb_subnet
  702. def delete(self, subnet):
  703. subnet_id = subnet.id if isinstance(subnet, AWSSubnet) else subnet
  704. return self.provider.vpc_conn.delete_subnet(subnet_id=subnet_id)