def create_connection(self): if self.conn is None: self.conn = ProviderController(self)
class Provider(models.Model): name = models.CharField(unique=True, max_length=25) provider_type = models.CharField( default='EC2_US_EAST', max_length=25, choices=PROVIDER_CHOICES) access_key = models.CharField("Access Key", max_length=100, blank=True) secret_key = models.CharField("Secret Key", max_length=100, blank=True) extra_param_name = models.CharField( "Extra parameter name", max_length=30, blank=True) extra_param_value = models.CharField( "Extra parameter value", max_length=30, blank=True) actions = models.ManyToManyField(Action) ready = models.BooleanField(default=False) conn = None class Meta: unique_together = ('provider_type', 'access_key') def save(self, *args, **kwargs): # Define proper key field names if PROVIDERS[self.provider_type]['access_key'] is not None: self._meta.get_field('access_key').verbose_name = \ PROVIDERS[self.provider_type]['access_key'] self._meta.get_field('access_key').blank = False if PROVIDERS[self.provider_type]['secret_key'] is not None: self._meta.get_field('secret_key').verbose_name = \ PROVIDERS[self.provider_type]['secret_key'] self._meta.get_field('access_key').blank = False # Read optional extra_param if 'extra_param' in PROVIDERS[self.provider_type].keys(): self.extra_param_name = PROVIDERS[self.provider_type]['extra_param'][0] self.extra_param_value = PROVIDERS[self.provider_type]['extra_param'][1] # Check connection and save new provider self.create_connection() # If connection was succesful save provider super(Provider, self).save(*args, **kwargs) logging.debug('Provider "%s" saved' % self.name) # Add supported actions for action_name in PROVIDERS[self.provider_type]['supported_actions']: try: action = Action.objects.get(name=action_name) except Action.DoesNotExist: raise Exception, 'Unsupported action "%s" specified' % action_name self.actions.add(action) def supports(self, action): try: self.actions.get(name=action) return True except Action.DoesNotExist: return False def create_connection(self): if self.conn is None: self.conn = ProviderController(self) @transaction.commit_on_success() def import_nodes(self): '''Sync nodes present at a provider with Overmind's DB''' if not self.supports('list'): return self.create_connection() nodes = self.conn.get_nodes() # Import nodes not present in the DB for node in nodes: try: n = Node.objects.get(provider=self, node_id=str(node.id)) except Node.DoesNotExist: # Create a new Node logging.info("import_nodes(): adding %s ..." % node) n = Node( name = node.name, node_id = str(node.id), provider = self, created_by = 'imported by Overmind', ) try: n.image = Image.objects.get( image_id=node.extra.get('imageId'), provider=self) except Image.DoesNotExist: n.image = None locs = Location.objects.filter(provider=self) if len(locs) == 1: n.location = locs[0] else: n.location = None try: size_id = node.extra.get('instancetype') or\ node.extra.get('flavorId') n.size = Size.objects.get(size_id=size_id, provider=self) except Size.DoesNotExist: n.size = None n.save() # Import/Update node info n.sync_ips(node.public_ips, public=True) n.sync_ips(node.private_ips, public=False) n.state = get_state(node.state) n.save_extra_data(node.extra) n.save() logging.debug("import_nodes(): succesfully saved %s" % node.name) # Delete nodes in the DB not listed by the provider for n in Node.objects.filter(provider=self ).exclude(environment='Decommissioned'): found = False for node in nodes: if n.node_id == str(node.id): found = True break # This node was probably removed from the provider by another tool # TODO: Needs user notification if not found: logging.info("import_nodes(): Delete node %s" % n) n.decommission() logging.debug("Finished synching nodes") @transaction.commit_on_success() def import_images(self): '''Get all images from this provider and store them in the DB The transaction.commit_on_success decorator is needed because some providers have thousands of images, which take a long time to save to the DB as separated transactions ''' if not self.supports('images'): return self.create_connection() for image in self.conn.get_images(): try: # Update image if it exists img = Image.objects.get(image_id=str(image.id), provider=self) except Image.DoesNotExist: # Create new image if it didn't exist img = Image( image_id = str(image.id), provider = self, ) img.name = image.name img.save() logging.debug( "Added new image '%s' for provider %s" % (img.name, self)) logging.info("Imported all images for provider %s" % self) @transaction.commit_on_success() def import_locations(self): '''Get all locations from this provider and store them in the DB''' if not self.supports('locations'): return self.create_connection() for location in self.conn.get_locations(): try: # Update location if it exists loc = Location.objects.get(location_id=str(location.id), provider=self) except Location.DoesNotExist: # Create new location if it didn't exist loc = Location( location_id = location.id, provider = self, ) loc.name = location.name loc.country = location.country loc.save() logging.debug( "Added new location '%s' for provider %s" % (loc.name, self)) logging.info("Imported all locations for provider %s" % self) @transaction.commit_on_success() def import_sizes(self): '''Get all sizes from this provider and store them in the DB''' if not self.supports('sizes'): return self.create_connection() sizes = self.conn.get_sizes() # Go through all sizes returned by the provider for size in sizes: try: # Read size s = Size.objects.get(size_id=str(size.id), provider=self) except Size.DoesNotExist: # Create new size if it didn't exist s = Size( size_id = str(size.id), provider = self, ) # Save/update size info s.name = size.name s.ram = size.ram s.disk = size.disk or "" s.bandwidth = size.bandwidth or "" s.price = size.price or "" s.save() logging.debug("Saved size '%s' for provider %s" % (s.name, self)) # Delete sizes in the DB not listed by the provider for s in self.get_sizes(): found = False for size in sizes: if s.size_id == str(size.id): found = True break # This size is probably not longer offered by the provider if not found: logging.debug("Deleted size %s" % s) s.delete() logging.debug("Finished synching sizes") def update(self): logging.debug('Updating provider "%s"...' % self.name) self.save() self.import_nodes() def check_credentials(self): if not self.supports('list'): return self.create_connection() self.conn.get_nodes() return True def get_sizes(self): return self.size_set.all() def get_images(self): return self.image_set.all() def get_fav_images(self): return self.image_set.filter(favorite=True).order_by('-last_used') def get_locations(self): return self.location_set.all() def create_node(self, data): self.create_connection() return self.conn.create_node(data) def reboot_node(self, node): self.create_connection() return self.conn.reboot_node(node) def destroy_node(self, node): self.create_connection() return self.conn.destroy_node(node) def __unicode__(self): return self.name