'Scale containers up or down to match requested structure.'

def scale(self, user, structure):

    if (self.release_set.latest().build is None):
        raise EnvironmentError(u'No    build    associated    with    this    release')
    requested_structure = structure.copy()
    release = self.release_set.latest()
    available_process_types = (release.build.procfile or {})
    for container_type in requested_structure:
        if (container_type == u'cmd'):
            continue
        if (container_type not in available_process_types):
            raise EnvironmentError(u'Container    type    {}    does    not    exist    in    application'.format(container_type))
    msg = (u'{}    scaled    containers    '.format(user.username) + u'    '.join((u'{}={}'.format(k, v) for (k, v) in requested_structure.items())))
    log_event(self, msg)
    changed = False
    (to_add, to_remove) = ([], [])
    scale_types = {}
    for container_type in requested_structure.keys():
        containers = list(self.container_set.filter(type=container_type).order_by(u'created'))
        results = self.container_set.filter(type=container_type).aggregate(Max(u'num'))
        container_num = ((results.get(u'num__max') or 0) + 1)
        requested = requested_structure.pop(container_type)
        diff = (requested - len(containers))
        if (diff == 0):
            continue
        changed = True
        scale_types[container_type] = requested
        while (diff < 0):
            c = containers.pop()
            to_remove.append(c)
            diff += 1
        while (diff > 0):
            c = Container.objects.create(owner=self.owner, app=self, release=release, type=container_type, num=container_num)
            to_add.append(c)
            container_num += 1
            diff -= 1
    if changed:
        if (u'scale' in dir(self._scheduler)):
            self._scale_containers(scale_types, to_remove)
        else:
            if to_add:
                self._start_containers(to_add)
            if to_remove:
                self._destroy_containers(to_remove)
    vals = self.container_set.exclude(type=u'run').values(u'type').annotate(Count(u'pk')).order_by()
    new_structure = structure.copy()
    new_structure.update({v[u'type']: v[u'pk__count'] for v in vals})
    self.structure = new_structure
    self.save()
    return changed
