Repository: deis/deis

Issue:
config:set error using int value
My fix in #1762 broke `deis config:set` when integer values are supplied. Need to add regression tests for that and fix it.

``` console
Syncing...
Creating tables ...
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
Migrating...
Running migrations for api:
- Nothing to migrate.
 - Loading initial data for api.
Installed 0 object(s) from 0 fixture(s)
Running migrations for guardian:
- Nothing to migrate.
 - Loading initial data for guardian.
Installed 0 object(s) from 0 fixture(s)

Synced:
 > django.contrib.admin
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.humanize
 > django.contrib.messages
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.staticfiles
 > allauth
 > allauth.account
 > django_fsm
 > json_field
 > rest_framework
 > south
 > web

Migrated:
 - api
 - guardian
deis-controller running...
2014-09-11 09:50:55 [82] [INFO] Starting gunicorn 18.0
2014-09-11 09:50:55 [82] [DEBUG] Arbiter booted
2014-09-11 09:50:55 [82] [INFO] Listening at: http://0.0.0.0:8000 (82)
2014-09-11 09:50:55 [82] [INFO] Using worker: sync
2014-09-11 09:50:55 [100] [INFO] Booting worker with pid: 100
2014-09-11 09:50:55 [104] [INFO] Booting worker with pid: 104
[2014-09-11 09:50:55,798: INFO/MainProcess] Connected to redis://10.0.1.97:6379/0
[2014-09-11 09:50:55,811: INFO/MainProcess] mingle: searching for neighbors
2014-09-11 09:50:55 [110] [INFO] Booting worker with pid: 110
2014-09-11 09:50:55 [111] [INFO] Booting worker with pid: 111
2014-09-11 09:50:55 [112] [INFO] Booting worker with pid: 112
2014-09-11 09:50:55 [125] [INFO] Booting worker with pid: 125
2014-09-11 09:50:56 [131] [INFO] Booting worker with pid: 131
2014-09-11 09:50:56 [132] [INFO] Booting worker with pid: 132
[2014-09-11 09:50:56,825: INFO/MainProcess] mingle: all alone
[2014-09-11 09:50:56,844: WARNING/MainProcess] celery@02a7167650ff ready.
2014-09-11 09:52:24 [131] [DEBUG] GET /api/apps/nested-doghouse
2014-09-11 09:52:24 [131] [DEBUG] GET /api/apps/nested-doghouse/containers
2014-09-11 09:52:24 [110] [DEBUG] GET /api/apps/nested-doghouse/domains
2014-09-11 09:52:28 [110] [DEBUG] POST /api/apps/nested-doghouse/config
INFO nested-doghouse: config nested-doghouse-a68e397 updated
INFO nested-doghouse: release nested-doghouse-v4 created
[2014-09-11 09:52:29,031: INFO/MainProcess] Received task: api.tasks.import_repository[b7ed11e7-3aef-4895-a2a2-f43c764c5f9a]
[2014-09-11 09:52:29,041: INFO/Worker-7] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:52:36,177: INFO/MainProcess] Task api.tasks.import_repository[b7ed11e7-3aef-4895-a2a2-f43c764c5f9a] succeeded in 7.143994355s: None
ERROR Internal Server Error: /api/apps/nested-doghouse/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 09:57:18 [111] [DEBUG] GET /api/apps/nested-doghouse
2014-09-11 09:57:18 [125] [DEBUG] GET /api/apps/nested-doghouse/containers
2014-09-11 09:57:18 [125] [DEBUG] GET /api/apps/nested-doghouse/domains
2014-09-11 09:57:24 [125] [DEBUG] POST /api/apps/nested-doghouse/config
INFO nested-doghouse: config nested-doghouse-978810e updated
INFO nested-doghouse: release nested-doghouse-v5 created
[2014-09-11 09:57:24,854: INFO/MainProcess] Received task: api.tasks.import_repository[a45cd995-875b-43df-bdcf-c24ef22702a9]
[2014-09-11 09:57:24,863: INFO/Worker-1] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:57:28,000: INFO/MainProcess] Task api.tasks.import_repository[a45cd995-875b-43df-bdcf-c24ef22702a9] succeeded in 3.144977735s: None
ERROR Internal Server Error: /api/apps/nested-doghouse/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 09:57:51 [112] [DEBUG] GET /api/apps/nested-doghouse/domains
2014-09-11 09:57:51 [112] [DEBUG] POST /api/apps/nested-doghouse/scale
2014-09-11 09:57:52 [112] [DEBUG] POST /api/apps/nested-doghouse/scale
2014-09-11 09:57:52 [132] [DEBUG] GET /api/apps/nested-doghouse
2014-09-11 09:57:52 [132] [DEBUG] GET /api/apps/nested-doghouse/containers
2014-09-11 09:57:52 [132] [DEBUG] GET /api/apps/nested-doghouse/domains
2014-09-11 09:57:53 [132] [DEBUG] DELETE /api/apps/nested-doghouse
2014-09-11 09:57:57 [132] [DEBUG] POST /api/apps
INFO lonely-daffodil: config lonely-daffodil-3279e95 updated
INFO lonely-daffodil: build lonely-daffodil-7fc1f05 created
INFO lonely-daffodil: release lonely-daffodil-v1 created
2014-09-11 09:58:09 [125] [DEBUG] POST /api/apps/lonely-daffodil/config
INFO lonely-daffodil: config lonely-daffodil-167227b updated
INFO lonely-daffodil: release lonely-daffodil-v2 created
[2014-09-11 09:58:09,518: INFO/MainProcess] Received task: api.tasks.import_repository[ad07d9f3-6df5-435c-be7e-7c9b26e83593]
[2014-09-11 09:58:09,527: INFO/Worker-5] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:58:11,704: INFO/MainProcess] Task api.tasks.import_repository[ad07d9f3-6df5-435c-be7e-7c9b26e83593] succeeded in 2.185258399s: None
[2014-09-11 09:58:12,059: INFO/MainProcess] Received task: api.tasks.deploy_release[9e6ce6a8-01a7-48c8-9f8e-a06b9498565e]
[2014-09-11 09:58:12,087: INFO/MainProcess] Task api.tasks.deploy_release[9e6ce6a8-01a7-48c8-9f8e-a06b9498565e] succeeded in 0.0258442939999s: None
2014-09-11 09:58:18 [132] [DEBUG] POST /api/apps/lonely-daffodil/config
INFO lonely-daffodil: config lonely-daffodil-e85d2d9 updated
INFO lonely-daffodil: release lonely-daffodil-v3 created
[2014-09-11 09:58:18,357: INFO/MainProcess] Received task: api.tasks.import_repository[8a8105a5-cfd3-4bed-bbf7-b519751f2b8d]
[2014-09-11 09:58:18,359: INFO/Worker-7] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:58:22,180: INFO/MainProcess] Task api.tasks.import_repository[8a8105a5-cfd3-4bed-bbf7-b519751f2b8d] succeeded in 3.82199411s: None
ERROR Internal Server Error: /api/apps/lonely-daffodil/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 09:59:06 [125] [DEBUG] POST /api/apps/lonely-daffodil/config
INFO lonely-daffodil: config lonely-daffodil-2cca4e5 updated
INFO lonely-daffodil: release lonely-daffodil-v4 created
[2014-09-11 09:59:06,835: INFO/MainProcess] Received task: api.tasks.import_repository[442b46ea-43d4-48be-9273-190412f61dbc]
[2014-09-11 09:59:06,837: INFO/Worker-1] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:59:10,681: INFO/MainProcess] Task api.tasks.import_repository[442b46ea-43d4-48be-9273-190412f61dbc] succeeded in 3.845249027s: None
ERROR Internal Server Error: /api/apps/lonely-daffodil/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 09:59:26 [132] [DEBUG] POST /api/apps/lonely-daffodil/config
INFO lonely-daffodil: config lonely-daffodil-586c380 updated
INFO lonely-daffodil: release lonely-daffodil-v5 created
[2014-09-11 09:59:26,490: INFO/MainProcess] Received task: api.tasks.import_repository[45ae8211-2935-4068-8071-ad30ce23619a]
[2014-09-11 09:59:26,493: INFO/Worker-5] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 09:59:30,450: INFO/MainProcess] Task api.tasks.import_repository[45ae8211-2935-4068-8071-ad30ce23619a] succeeded in 3.958495063s: None
ERROR Internal Server Error: /api/apps/lonely-daffodil/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 09:59:33 [125] [DEBUG] GET /api/apps/lonely-daffodil
2014-09-11 09:59:34 [104] [DEBUG] GET /api/apps/lonely-daffodil/containers
2014-09-11 09:59:34 [104] [DEBUG] GET /api/apps/lonely-daffodil/domains
2014-09-11 09:59:38 [104] [DEBUG] GET /api/apps/lonely-daffodil/config
2014-09-11 09:59:46 [100] [DEBUG] GET /api/apps/lonely-daffodil/domains
2014-09-11 09:59:47 [100] [DEBUG] POST /api/apps/lonely-daffodil/scale
2014-09-11 09:59:47 [132] [DEBUG] POST /api/apps/lonely-daffodil/scale
2014-09-11 09:59:48 [112] [DEBUG] GET /api/apps/lonely-daffodil
2014-09-11 09:59:48 [104] [DEBUG] GET /api/apps/lonely-daffodil/containers
2014-09-11 09:59:48 [111] [DEBUG] GET /api/apps/lonely-daffodil/domains
2014-09-11 09:59:48 [125] [DEBUG] DELETE /api/apps/lonely-daffodil
2014-09-11 09:59:56 [131] [DEBUG] POST /api/apps
INFO bolder-undertow: config bolder-undertow-77a6b76 updated
INFO bolder-undertow: build bolder-undertow-961f0ef created
INFO bolder-undertow: release bolder-undertow-v1 created
2014-09-11 10:00:36 [125] [DEBUG] GET /api/apps/bolder-undertow
2014-09-11 10:00:36 [131] [DEBUG] GET /api/apps/bolder-undertow/containers
2014-09-11 10:00:36 [111] [DEBUG] GET /api/apps/bolder-undertow/domains
2014-09-11 10:00:40 [104] [DEBUG] POST /api/apps/bolder-undertow/config
INFO bolder-undertow: config bolder-undertow-0444cd6 updated
INFO bolder-undertow: release bolder-undertow-v2 created
[2014-09-11 10:00:40,999: INFO/MainProcess] Received task: api.tasks.import_repository[2f6ac447-35ab-42de-b0b8-fd6c1717b395]
[2014-09-11 10:00:41,004: INFO/Worker-2] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 10:00:51,473: INFO/MainProcess] Task api.tasks.import_repository[2f6ac447-35ab-42de-b0b8-fd6c1717b395] succeeded in 10.473212297s: None
ERROR Internal Server Error: /api/apps/bolder-undertow/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
2014-09-11 10:01:07 [111] [DEBUG] POST /api/apps/bolder-undertow/config
INFO bolder-undertow: config bolder-undertow-4786b5a updated
INFO bolder-undertow: release bolder-undertow-v3 created
[2014-09-11 10:01:07,314: INFO/MainProcess] Received task: api.tasks.import_repository[207fcef4-9c82-40d0-96c4-90a66d664190]
[2014-09-11 10:01:07,317: INFO/Worker-7] Starting new HTTP connection (1): 10.0.1.97
[2014-09-11 10:01:08,948: INFO/MainProcess] Task api.tasks.import_repository[207fcef4-9c82-40d0-96c4-90a66d664190] succeeded in 1.632750608s: None
ERROR Internal Server Error: /api/apps/bolder-undertow/config
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/viewsets.py", line 78, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/csrf.py", line 57, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 400, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/views.py", line 397, in dispatch
    response = handler(request, *args, **kwargs)
  File "/app/api/views.py", line 325, in create
    return super(AppConfigViewSet, self).create(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/mixins.py", line 55, in create
    self.post_save(self.object, created=True)
  File "/app/api/views.py", line 298, in post_save
    self.release = release.new(self.request.user, config=config)
  File "/app/api/models.py", line 553, in new
    release_image,)
  File "/app/registry/private.py", line 56, in publish_release
    image['config']['Env'] = _construct_env(image['config']['Env'], config)
  File "/app/registry/private.py", line 172, in _construct_env
    new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
AttributeError: 'int' object has no attribute 'encode'
```



Discussion:
would casting to a string on the k & v fix this? 


Resolving patch:
diff --git a/client/deis.py b/client/deis.py
--- a/client/deis.py
+++ b/client/deis.py
@@ -303,6 +303,14 @@ def dictify(args):
     return data
 
 
+def encode(obj):
+    """Return UTF-8 encoding for string objects."""
+    if isinstance(obj, basestring):
+        return obj.encode('utf-8')
+    else:
+        return obj
+
+
 def readable_datetime(datetime_str):
     """
     Return a human-readable datetime string from an ECMA-262 (JavaScript)
@@ -1122,14 +1130,12 @@ def config_list(self, args):
             if not oneline:
                 width = max(map(len, keys)) + 5
                 for k in keys:
-                    v = values[k]
-                    k, v = k.encode('utf-8'), v.encode('utf-8')
+                    k, v = encode(k), encode(values[k])
                     self._logger.info(("{k:<" + str(width) + "} {v}").format(**locals()))
             else:
                 output = []
                 for k in keys:
-                    v = values[k]
-                    k, v = k.encode('utf-8'), v.encode('utf-8')
+                    k, v = encode(k), encode(values[k])
                     output.append("{k}={v}".format(**locals()))
                 self._logger.info(' '.join(output))
         else:
@@ -1175,8 +1181,7 @@ def config_set(self, args):
                 self._logger.info('No configuration')
                 return
             for k, v in values.items():
-                k, v = k.encode('utf-8'), v.encode('utf-8')
-                self._logger.info("{k}: {v}".format(**locals()))
+                self._logger.info("{}: {}".format(encode(k), encode(v)))
         else:
             raise ResponseError(response)
 
diff --git a/controller/api/utils.py b/controller/api/utils.py
--- a/controller/api/utils.py
+++ b/controller/api/utils.py
@@ -108,6 +108,14 @@ def fingerprint(key):
     return ':'.join(a + b for a, b in zip(fp_plain[::2], fp_plain[1::2]))
 
 
+def encode(obj):
+    """Return UTF-8 encoding for string objects."""
+    if isinstance(obj, basestring):
+        return obj.encode('utf-8')
+    else:
+        return obj
+
+
 if __name__ == "__main__":
     import doctest
     doctest.testmod()
diff --git a/controller/registry/private.py b/controller/registry/private.py
--- a/controller/registry/private.py
+++ b/controller/registry/private.py
@@ -6,9 +6,10 @@
 import urlparse
 import uuid
 
+from django.conf import settings
 from docker.utils import utils
 
-from django.conf import settings
+from api.utils import encode
 
 
 def publish_release(source, config, target):
@@ -158,7 +159,6 @@ def _put_tag(image_id, repository_path, tag):
 
 # utility functions
 
-
 def _construct_env(env, config):
     "Update current environment with latest config"
     new_env = []
@@ -168,10 +168,10 @@ def _construct_env(env, config):
         if k in config:
             # update values defined by config
             v = config.pop(k)
-        new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
+        new_env.append("{}={}".format(encode(k), encode(v)))
     # add other config ENV items
     for k, v in config.items():
-        new_env.append("{}={}".format(k.encode('utf-8'), v.encode('utf-8')))
+        new_env.append("{}={}".format(encode(k), encode(v)))
     return new_env
 
 


Test patch:
diff --git a/controller/api/tests/test_config.py b/controller/api/tests/test_config.py
--- a/controller/api/tests/test_config.py
+++ b/controller/api/tests/test_config.py
@@ -148,6 +148,12 @@ def test_config_set_unicode(self):
         self.assertEqual(response.status_code, 201)
         self.assertIn('POWERED_BY', json.loads(response.data['values']))
         self.assertEqual(json.loads(response.data['values'])['POWERED_BY'], 'Кроликов')
+        # set an integer to test unicode regression
+        body = {'values': json.dumps({'INTEGER': 1})}
+        response = self.client.post(url, json.dumps(body), content_type='application/json')
+        self.assertEqual(response.status_code, 201)
+        self.assertIn('INTEGER', json.loads(response.data['values']))
+        self.assertEqual(json.loads(response.data['values'])['INTEGER'], 1)
 
     @mock.patch('requests.post', mock_import_repository_task)
     def test_config_str(self):
diff --git a/tests/config_test.go b/tests/config_test.go
--- a/tests/config_test.go
+++ b/tests/config_test.go
@@ -11,6 +11,7 @@ import (
 var (
 	configListCmd  = "config:list --app={{.AppName}}"
 	configSetCmd   = "config:set FOO=讲台 --app={{.AppName}}"
+	configSet2Cmd  = "config:set FOO=10 --app={{.AppName}}"
 	configUnsetCmd = "config:unset FOO --app={{.AppName}}"
 )
 
@@ -52,11 +53,13 @@ func configListTest(
 }
 
 func configSetTest(t *testing.T, params *utils.DeisTestConfig) {
-	utils.Execute(t, configSetCmd, params, false, "")
+	utils.Execute(t, configSetCmd, params, false, "讲台")
 	utils.CheckList(t, appsInfoCmd, params, "(v3)", false)
+	utils.Execute(t, configSet2Cmd, params, false, "10")
+	utils.CheckList(t, appsInfoCmd, params, "(v4)", false)
 }
 
 func configUnsetTest(t *testing.T, params *utils.DeisTestConfig) {
 	utils.Execute(t, configUnsetCmd, params, false, "")
-	utils.CheckList(t, appsInfoCmd, params, "(v4)", false)
+	utils.CheckList(t, appsInfoCmd, params, "(v5)", false)
 }