internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: deis/deis

Issue:
Update to Django 1.6
Better, faster, stronger. Only real issue seems to be in South `./manage.py migrate --noinput` raising an error about auth.User model not being installed...



Discussion:

Resolving patch:
diff --git a/api/models.py b/api/models.py
--- a/api/models.py
+++ b/api/models.py
@@ -83,7 +83,6 @@ def delete(self, *args, **kwargs):
         self.owner.publish()
 
 
-@python_2_unicode_compatible
 class ProviderManager(models.Manager):
     """Manage database interactions for :class:`Provider`."""
 
@@ -126,7 +125,6 @@ def __str__(self):
         return "{}-{}".format(self.id, self.get_type_display())
 
 
-@python_2_unicode_compatible
 class FlavorManager(models.Manager):
     """Manage database interactions for :class:`Flavor`."""
 
@@ -292,7 +290,6 @@ def destroy(self):
         return tasks.destroy_layer.delay(self).wait()
 
 
-@python_2_unicode_compatible
 class NodeManager(models.Manager):
 
     def new(self, formation, layer, fqdn=None):
@@ -537,7 +534,6 @@ def run(self, command):
         return node.run(command)
 
 
-@python_2_unicode_compatible
 class ContainerManager(models.Manager):
 
     def scale(self, app, structure, **kwargs):
@@ -733,7 +729,7 @@ def push(cls, push):
         # create the build
         new_build = cls.objects.create(**push)
         # send a release signal
-        release_signal.send(sender=push, build=new_build, app=app, user=user)
+        release_signal.send(sender=user, build=new_build, app=app, user=user)
         # see if we need to scale an initial web container
         if len(app.formation.node_set.filter(layer__runtime=True)) > 0 and \
            len(app.container_set.filter(type='web')) < 1:
diff --git a/deis/settings.py b/deis/settings.py
--- a/deis/settings.py
+++ b/deis/settings.py
@@ -29,6 +29,8 @@
     }
 }
 
+CONN_MAX_AGE = 60 * 3
+
 # Hosts/domain names that are valid for this site; required if DEBUG is False
 # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
 ALLOWED_HOSTS = ['localhost']
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -20,12 +20,10 @@
 #sys.path.insert(0, os.path.abspath('.'))
 sys.path.insert(0, os.path.abspath('..'))
 # set up Django
-from deis import settings
-from django.core.management import setup_environ
-
+os.environ['DJANGO_SETTINGS_MODULE'] = 'deis.settings'
+from django.conf import settings
 if not settings.SECRET_KEY:
     settings.SECRET_KEY = 'TotallyFake-SECRET_KEY-ForSphinxDocs'
-setup_environ(settings)
 
 # -- General configuration -----------------------------------------------------
 


Test patch:
Repository: deis/deis

Issue:
Query for Layer is wrong in build_layer()
Several provider implementations need to update the Layer model, but fetch it with this query:

``` python
def build_layer(layer):
    """
    Build a layer.

    :param layer: a dict containing formation, id, params, and creds info
    """
    layer_ = Layer.objects.get(id=layer['id'])
    layer_.ssh_username = 'vagrant'
    layer_.save()
```

But the **id** field is _not_ the primary key--that would be **uuid**. So it's easy to get a MultipleObjectsReturned error if there are two "runtime" layers around, for example. Need to fix the query to actually select a single row.



Discussion:

Resolving patch:
diff --git a/provider/digitalocean.py b/provider/digitalocean.py
--- a/provider/digitalocean.py
+++ b/provider/digitalocean.py
@@ -43,7 +43,7 @@ def build_layer(layer):
     params = {'name': name, 'ssh_pub_key': layer['ssh_public_key']}
     conn.request('/ssh_keys/new/', method='GET', params=params)
     # Digital Ocean images only have the root user created by default
-    l = Layer.objects.get(id=layer['id'])
+    l = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])
     l.ssh_username = 'root'
     l.save()
 
diff --git a/provider/rackspace.py b/provider/rackspace.py
--- a/provider/rackspace.py
+++ b/provider/rackspace.py
@@ -59,8 +59,7 @@ def build_layer(layer):
     # import a new keypair using the layer key material
     conn.keypairs.create(name, layer['ssh_public_key'])
     # Rackspace images only have the root user created by default
-    # TODO: this seems like a smelly hack...
-    layer_ = Layer.objects.get(id=layer['id'])
+    layer_ = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])
     layer_.ssh_username = 'root'
     layer_.save()
 
diff --git a/provider/vagrant.py b/provider/vagrant.py
--- a/provider/vagrant.py
+++ b/provider/vagrant.py
@@ -50,7 +50,7 @@ def build_layer(layer):
     """
 
     # This can also be done with `deis layers:update` now.
-    layer_ = Layer.objects.get(id=layer['id'])
+    layer_ = Layer.objects.get(id=layer['id'], formation__id=layer['formation'])
     layer_.ssh_username = 'vagrant'
     layer_.save()
 


Test patch:
Repository: deis/deis

Issue:
Vagrant provider repeatedly errors on formation if node dir is deleted
Needs to be more robust in some error cases such as this one:
1) Provision a controller but somehow forget to add _deis-controler_ to the admins group, despite all documentation and fuschia-colored warnings at the command-line
2) Create a formation and scale it upward, e.g. `deis nodes:scale form1 runtime=2`
3) Try to scale down the formation, get an appropriate error about "couldn't remove chef node"
4) All subsequent formation commands--including destroy!--will fail when trying to access the local vagrant node dir, which apparently was removed in step 3).

This shouldn't happen often, but it can and I think ignoring this error at least in the case of `deis formations:destroy` would provide a way out of this dead end.



Discussion:

Resolving patch:
diff --git a/provider/vagrant.py b/provider/vagrant.py
--- a/provider/vagrant.py
+++ b/provider/vagrant.py
@@ -131,17 +131,25 @@ def destroy_node(node):
         return
 
     # Shut the VM down and destroy it
-    _run_vagrant_command(node['provider_id'], args=['destroy', '--force'], creds=node['creds'])
-    node_dir = HOST_NODES_DIR + '/' + node['provider_id']
-
-    # Sanity check before `rm -rf`
-    if 'contrib/vagrant' not in node_dir:
-        raise RuntimeError("Aborted node destruction: attempting to 'rm -rf' unexpected directory")
-
-    # Completely remove the folder that contained the VM
-    rm_vagrantfile = 'rm ' + node_dir + '/Vagrantfile'
-    rm_node_dir = 'rm -rf ' + node_dir
-    _host_ssh(commands=[rm_vagrantfile, rm_node_dir], creds=node['creds'])
+    try:
+        _run_vagrant_command(node['provider_id'], args=['destroy', '--force'], creds=node['creds'])
+        node_dir = HOST_NODES_DIR + '/' + node['provider_id']
+
+        # Sanity check before `rm -rf`
+        if 'contrib/vagrant' not in node_dir:
+            raise RuntimeError(
+                "Aborted node destruction: attempting to 'rm -rf' unexpected directory")
+
+        # Completely remove the folder that contained the VM
+        rm_vagrantfile = 'rm ' + node_dir + '/Vagrantfile'
+        rm_node_dir = 'rm -rf ' + node_dir
+        _host_ssh(commands=[rm_vagrantfile, rm_node_dir], creds=node['creds'])
+    except RuntimeError as err:
+        # If we couldn't cd to the node dir, just log that as a warning
+        if 'No such file or directory' in str(err):
+            logger.warn(err)
+        else:
+            raise
 
 
 def _run_vagrant_command(node_id, args=[], creds={}):


Test patch:
Repository: deis/deis

Issue:
Update EC2 AMIs for 0.3.0 release



Discussion:

Resolving patch:
diff --git a/api/models.py b/api/models.py
--- a/api/models.py
+++ b/api/models.py
@@ -531,6 +531,7 @@ def logs(self):
 
     def run(self, command):
         """Run a one-off command in an ephemeral app container."""
+        # TODO: add support for interactive shell
         nodes = self.formation.node_set.filter(layer__runtime=True).order_by('?')
         if not nodes:
             raise EnvironmentError('No nodes available to run command')
@@ -539,12 +540,9 @@ def run(self, command):
         # prepare ssh command
         version = release.version
         docker_args = ' '.join(
-            ['-v',
-             '/opt/deis/runtime/slugs/{app_id}-{version}/app:/app'.format(**locals()),
-             release.build.image])
-        base_cmd = "export HOME=/app; cd /app && for profile in " \
-                   "`find /app/.profile.d/*.sh -type f`; do . $profile; done"
-        command = "/bin/sh -c '{base_cmd} && {command}'".format(**locals())
+            ['-a', 'stdout', '-a', 'stderr',
+             '-v', '/opt/deis/runtime/slugs/{app_id}-v{version}:/app'.format(**locals()),
+             'deis/slugrunner'])
         command = "sudo docker run {docker_args} {command}".format(**locals())
         return node.run(command)
 
diff --git a/provider/ec2.py b/provider/ec2.py
--- a/provider/ec2.py
+++ b/provider/ec2.py
@@ -17,14 +17,14 @@
 # Deis-optimized EC2 amis -- with 3.8 kernel, chef 11 deps,
 # and large docker images (e.g. buildstep) pre-installed
 IMAGE_MAP = {
-    'ap-northeast-1': 'ami-2bd9bf2a',
-    'ap-southeast-1': 'ami-2821757a',
-    'ap-southeast-2': 'ami-4dfd6277',
-    'eu-west-1': 'ami-0452be73',
-    'sa-east-1': 'ami-87f9589a',
-    'us-east-1': 'ami-5f84a536',
-    'us-west-1': 'ami-f80c3dbd',
-    'us-west-2': 'ami-76ad3746',
+    'ap-northeast-1': 'ami-6399f962',
+    'ap-southeast-1': 'ami-0a87d358',
+    'ap-southeast-2': 'ami-c3bd22f9',
+    'eu-west-1': 'ami-4826c83f',
+    'sa-east-1': 'ami-79bf1e64',
+    'us-east-1': 'ami-e7af828e',
+    'us-west-1': 'ami-a06e5ee5',
+    'us-west-2': 'ami-28abce18',
 }
 
 


Test patch:
Repository: deis/deis

Issue:
Environment variables are not consistently available to deployed apps
Found the issue with a Django App that did not respect database env vars. However they seem to work with our existing example apps.

```
$ deis config
=== <appName> Config
POWERED_BY: Gabe

$ deis run 'echo $POWERED_BY'
<returns blank>
```

Django Traceback

```
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:     mod = importlib.import_module(self.SETTINGS_MODULE)
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:   File "/app/.heroku/python/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:     __import__(name)
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:   File "/app/django_crud_app/settings.py", line 74, in <module>
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:     'HOST': os.environ['HOST'],
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:   File "/app/.heroku/python/lib/python2.7/UserDict.py", line 23, in __getitem__
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]:     raise KeyError(key)
Dec  3 22:21:43 ip-172-31-8-199 rubber-nuthatch[web.1]: KeyError: 'HOST'
```



Discussion:
@bengrunfeld, what Django app are you using, and what's the best way to recreate this bug?

@bacongobbler, I'm using the Django app that I wrote for Deis. It's just a basic CRUD app. You can find it at:
[https://github.com/bengrunfeld/example-python-django-crud-app](https://github.com/bengrunfeld/example-python-django-crud-app)

Super easy to recreate the bug.

Just go to one of your existing apps and do the following:

```
$ deis config:set VAR=value     #set an env var
$ deis config                   #check that its set
$ deis run 'echo $VAR'          #will return blank, meaning that it's not completely set.
```

However, the environment variable change does seem to propagate to the server process: use POWERED_BY as an example and you'll see the banner change. So it may be something specific to `deis run`.

We need to re-test this with the new slugrunner in 0.3.

I did, and it still acted as described unfortunately (`deis config:set` works for the app, but doesn't show up in `deis run`.)


Resolving patch:
diff --git a/api/models.py b/api/models.py
--- a/api/models.py
+++ b/api/models.py
@@ -541,10 +541,12 @@ def run(self, command):
         # prepare ssh command
         version = release.version
         docker_args = ' '.join(
-            ['-a', 'stdout', '-a', 'stderr',
+            ['-a', 'stdout', '-a', 'stderr', '-rm',
              '-v', '/opt/deis/runtime/slugs/{app_id}-v{version}:/app'.format(**locals()),
              'deis/slugrunner'])
-        command = "sudo docker run {docker_args} {command}".format(**locals())
+        env_args = ' '.join(["-e '{k}={v}'".format(**locals())
+                             for k, v in release.config.values.items()])
+        command = "sudo docker run {env_args} {docker_args} {command}".format(**locals())
         return node.run(command)
 
 


Test patch:
Repository: deis/deis

Issue:
Documentation for `deis sharing` commands
We need more detailed docstrings, as well as a short tutorial section on sharing apps.



Discussion:

Resolving patch:
diff --git a/client/deis.py b/client/deis.py
--- a/client/deis.py
+++ b/client/deis.py
@@ -1671,6 +1671,9 @@ def perms(self, args):
 
     def perms_list(self, args):
         """
+        List all users with permission to use an app, or list all users
+        with system administrator privileges.
+
         Usage: deis perms:list [--app=<app>|--admin]
         """
         app, url = self._parse_perms_args(args)
@@ -1682,6 +1685,9 @@ def perms_list(self, args):
 
     def perms_create(self, args):
         """
+        Give another user permission to use an app, or give another user
+        system administrator privileges.
+
         Usage: deis perms:create <username> [--app=<app>|--admin]
         """
         app, url = self._parse_perms_args(args)
@@ -1701,6 +1707,9 @@ def perms_create(self, args):
 
     def perms_delete(self, args):
         """
+        Revoke another user's permission to use an app, or revoke another
+        user's system administrator privileges.
+
         Usage: deis perms:delete <username> [--app=<app>|--admin]
         """
         app, url = self._parse_perms_args(args)


Test patch:
Repository: deis/deis

Issue:
Delete EC2 formation leaves garbage at EC2
You can sucessufully delete a EC2 formation, but later you have no way to create another with the same ID, as there will still exist a Security Group and Key Pair with same name on EC2



Discussion:
It's definitely a bug because we should be destroying that security group in `destroy_layer`:
https://github.com/opdemand/deis/blob/master/provider/ec2.py#L93

We need to find a more robust way of working around this EC2 race condition.

I found the other error we're not catching here:
http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteSecurityGroup.html

It's `DependencyViolation`.  We also need to loop to make sure we handle the race condition.


Resolving patch:
diff --git a/provider/ec2.py b/provider/ec2.py
--- a/provider/ec2.py
+++ b/provider/ec2.py
@@ -87,13 +87,20 @@ def destroy_layer(layer):
     conn.delete_key_pair(name)
     # there's an ec2 race condition on instances terminating
     # successfully but still holding a lock on the security group
-    # let's take a nap
-    time.sleep(5)
-    try:
-        conn.delete_security_group(name)
-    except EC2ResponseError as e:
-        if e.code != 'InvalidGroup.NotFound':
-            raise e
+    for i in range(5):
+        # let's take a nap
+        time.sleep(i ** 1.25)  # 1, 2.4, 3.9, 5.6, 7.4
+        try:
+            conn.delete_security_group(name)
+            return
+        except EC2ResponseError as err:
+            if err.code == 'InvalidGroup.NotFound':
+                return
+            elif err.code in ('InvalidGroup.InUse',
+                              'DependencyViolation') and i < 4:
+                continue  # retry
+            else:
+                raise
 
 
 def build_node(node):


Test patch:
Repository: deis/deis

Issue:
permalinks in the documentation
It would be nice to permalink a specific header in the Deis documentation, much like how Stackato's documentation is built: http://docs.stackato.com/client/index.html#getting-help

This is probably a flag set somewhere in Sphinx to get this set up, but would be awesome for referential purposes on IRC or by email.



Discussion:
+1. The HTML ID's are in the markup already:

```
<div class="section" id="clone-the-deis-repository">
<h2>Clone the Deis Repository</h2>
...
</div>
```

We just need to inject permalinks to the anchors somehow.  Javascript post processing maybe?


Resolving patch:
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -147,7 +147,7 @@
 # typographically correct entities.
 html_use_smartypants = True
 
-html_add_permalinks = None
+html_add_permalinks = True
 
 # Custom sidebar templates, maps document names to template names.
 #html_sidebars = {}


Test patch:
Repository: deis/deis

Issue:
`deis releases:info --version=X` always returns latest version
We seem to be ignoring the version flag. Need to fix this in the viewset class.



Discussion:

Resolving patch:
diff --git a/api/views.py b/api/views.py
--- a/api/views.py
+++ b/api/views.py
@@ -587,6 +587,10 @@ class AppReleaseViewSet(BaseAppViewSet):
     model = models.Release
     serializer_class = serializers.ReleaseSerializer
 
+    def get_object(self, *args, **kwargs):
+        """Get Release by version always."""
+        return self.get_queryset(**kwargs).get(version=self.kwargs['version'])
+
 
 class AppContainerViewSet(OwnerViewSet):
     """RESTful views for :class:`~api.models.Container`."""


Test patch:
diff --git a/api/tests/test_release.py b/api/tests/test_release.py
--- a/api/tests/test_release.py
+++ b/api/tests/test_release.py
@@ -120,6 +120,14 @@ def test_release(self):
         self.assertIn('PATH', config3_values)
         self.assertEqual(
             config3_values['PATH'], 'bin:/usr/local/bin:/usr/bin:/bin')
+        # check that we can fetch a previous release
+        url = '/api/apps/{app_id}/releases/2'.format(**locals())
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        release2 = response.data
+        self.assertNotEqual(release2['uuid'], release3['uuid'])
+        self.assertNotEqual(release2['build'], release3['build'])
+        self.assertEquals(release2['version'], 2)
         # disallow post/put/patch/delete
         url = '/api/apps/{app_id}/releases'.format(**locals())
         self.assertEqual(self.client.post(url).status_code, 405)
Repository: deis/deis

Issue:
`deis config:list` shows latest Config created, not current Config
When I added `deis rollback`, I didn't realize that we were making an assumption in models.BaseAppViewSet that it could always fetch the latest Config. This fails after rollback. Need to rework the viewsets' get_object() to fetch via `app.release_set.latest().config` or somesuch.



Discussion:

Resolving patch:
diff --git a/api/views.py b/api/views.py
--- a/api/views.py
+++ b/api/views.py
@@ -579,6 +579,14 @@ class AppConfigViewSet(BaseAppViewSet):
     model = models.Config
     serializer_class = serializers.ConfigSerializer
 
+    def get_object(self, *args, **kwargs):
+        """Return the Config associated with the App's latest Release."""
+        app = get_object_or_404(models.App, id=self.kwargs['id'])
+        user = self.request.user
+        if user == app.owner or user in get_users_with_perms(app):
+            return app.release_set.latest().config
+        raise PermissionDenied()
+
     def post_save(self, obj, created=False):
         if created:
             models.release_signal.send(


Test patch:
diff --git a/api/tests/test_release.py b/api/tests/test_release.py
--- a/api/tests/test_release.py
+++ b/api/tests/test_release.py
@@ -210,6 +210,25 @@ def test_release_rollback(self):
         self.assertNotEqual(release1['uuid'], release5['uuid'])
         self.assertEqual(release1['build'], release5['build'])
         self.assertEqual(release1['config'], release5['config'])
+        # check to see that the current config is actually the initial one
+        url = "/api/apps/{app_id}/config".format(**locals())
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.data['values'], json.dumps({}))
+        # rollback to #3 and see that it has the correct config
+        url = "/api/apps/{app_id}/releases/rollback/".format(**locals())
+        body = {'version': 3}
+        response = self.client.post(
+            url, json.dumps(body), content_type='application/json')
+        self.assertEqual(response.status_code, 201)
+        url = "/api/apps/{app_id}/config".format(**locals())
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        values = json.loads(response.data['values'])
+        self.assertIn('NEW_URL1', values)
+        self.assertEqual('http://localhost:8080/', values['NEW_URL1'])
+        self.assertIn('PATH', values)
+        self.assertEqual('bin:/usr/local/bin:/usr/bin:/bin', values['PATH'])
 
     def test_release_str(self):
         """Test the text representation of a release."""
Repository: deis/deis

Issue:
Layers update doesn't respect existing values
If you `layers:update` without specifying all options, defaults will overwrite, for example, `ssh_username` even if it was set previously.



Discussion:

Resolving patch:
diff --git a/client/deis.py b/client/deis.py
--- a/client/deis.py
+++ b/client/deis.py
@@ -1496,18 +1496,18 @@ def layers_list(self, args):
 
     def layers_update(self, args):
         """
-        Create a layer of nodes
+        Update a layer of nodes
 
         Usage: deis layers:update <formation> <id> [options]
 
         Options:
 
-        --proxy=<yn>                    layer can be used for proxy [default: y]
-        --runtime=<yn>                  layer can be used for runtime [default: y]
-        --ssh_username=USERNAME         username for ssh connections [default: ubuntu]
-        --ssh_private_key=PRIVATE_KEY   private key for ssh comm (default: auto-gen)
-        --ssh_public_key=PUBLIC_KEY     public key for ssh comm (default: auto-gen)
-        --ssh_port=<port>               port number for ssh comm (default: 22)
+        --proxy=<yn>                    layer can be used for proxy
+        --runtime=<yn>                  layer can be used for runtime
+        --ssh_username=USERNAME         username for ssh connections
+        --ssh_private_key=PRIVATE_KEY   private key for ssh comm
+        --ssh_public_key=PUBLIC_KEY     public key for ssh comm
+        --ssh_port=<port>               port number for ssh comm
 
         """
         formation = args.get('<formation>')


Test patch:
diff --git a/api/tests/test_layer.py b/api/tests/test_layer.py
--- a/api/tests/test_layer.py
+++ b/api/tests/test_layer.py
@@ -66,10 +66,17 @@ def test_layer(self):
         response = self.client.get(url)
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.data['id'], layer_id)
-        body = {'config': {'new': 'value'}}
+        body = {'ssh_username': 'otto_test', 'config': {'new': 'value'}}
         response = self.client.patch(url, json.dumps(body), content_type='application/json')
         self.assertEqual(response.status_code, 200)
+        self.assertEqual('otto_test', response.data['ssh_username'])
         self.assertIn('new', response.data['config'])
+        body = {'ssh_port': 9999, 'runtime': False}
+        response = self.client.patch(url, json.dumps(body), content_type='application/json')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual('otto_test', response.data['ssh_username'])
+        self.assertEqual(9999, response.data['ssh_port'])
+        self.assertFalse(response.data['runtime'])
         response = self.client.delete(url)
         self.assertEqual(response.status_code, 204)