Repository: localstack/localstack

Issue:
Errors deleting SQS queue
Using the :latest localstack, attempts to delete an SQS queue fail with the following error logged to the console.

```localstack_1                          | 2020-02-11T19:04:08:ERROR:localstack.services.generic_proxy: Error forwarding request: 'Attribute.1.Value' Traceback (most recent call last):
localstack_1                          |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 248, in forward
localstack_1                          |     path=path, data=data, headers=forward_headers)
localstack_1                          |   File "/opt/code/localstack/.venv/lib/python3.7/site-packages/localstack_ext/services/sqs/sqs_extended.py", line 30, in forward_request
localstack_1                          |   File "/opt/code/localstack/localstack/services/sqs/sqs_listener.py", line 60, in forward_request
localstack_1                          |     self._set_queue_attributes(queue_url, req_data)
localstack_1                          |   File "/opt/code/localstack/.venv/lib/python3.7/site-packages/localstack_ext/services/sqs/sqs_extended.py", line 73, in _set_queue_attributes
localstack_1                          |   File "/opt/code/localstack/localstack/services/sqs/sqs_listener.py", line 275, in _set_queue_attributes
localstack_1                          |     attrs = self._format_attributes(req_data)
localstack_1                          |   File "/opt/code/localstack/localstack/services/sqs/sqs_listener.py", line 237, in _format_attributes
localstack_1                          |     key_value = req_data[key2][0]
localstack_1                          | KeyError: 'Attribute.1.Value'```

I'm using terraform to manage my SQS queues and the deletion was triggered by renaming the queue.
Failed to start on Windows - ERROR: environment can only contain strings
**F:\\*\*\*>pip install localstack**
```
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found a
t https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting localstack
  Downloading https://files.pythonhosted.org/packages/b8/79/adf5f3b968646cded524491e97028602be0c23f0c1736bb6e3614de9911b/localstack-0.10.6.tar.gz (270kB)
     |????????????????????????????????| 276kB 264kB/s
Collecting boto3>=1.9.71 (from localstack)
  Downloading https://files.pythonhosted.org/packages/30/87/7e8f268e7b3a5dfe67dc52790cc6f4c04a6670a02b31716961eb9ac8278c/boto3-1.10.43-py2.py3-none-any.whl (128kB)
     |????????????????????????????????| 133kB 2.0MB/s
Collecting dnspython==1.16.0 (from localstack)
  Downloading https://files.pythonhosted.org/packages/ec/d3/3aa0e7213ef72b8585747aa0e271a9523e713813b9a20177ebe1e939deb0/dnspython-1.16.0-py2.py3-none-any.whl (188kB)
     |????????????????????????????????| 194kB 2.0MB/s
Collecting docopt>=0.6.2 (from localstack)
  Downloading https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz
Collecting localstack-ext>=0.10.51 (from localstack)
  Downloading https://files.pythonhosted.org/packages/85/37/bb2a17c099a1a8d6420b11e49a6906db41a6ebb2115f9eadebb99bd5ad68/localstack-ext-0.10.87.tar.gz (214kB)
     |????????????????????????????????| 215kB 2.0MB/s
Collecting localstack-client>=0.14 (from localstack)
  Downloading https://files.pythonhosted.org/packages/32/fe/0bb7781b5c6f50b8d92dbeba97e7ee66d15ef638a5c6b5c1c017f3829266/localstack-client-0.15.tar.gz
Collecting requests>=2.20.0 (from localstack)
  Downloading https://files.pythonhosted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/requests-2.22.0-py2.py3-none-any.whl (57kB)
     |????????????????????????????????| 61kB 1.4MB/s
Collecting six>=1.12.0 (from localstack)
  Downloading https://files.pythonhosted.org/packages/65/26/32b8464df2a97e6dd1b656ed26b2c194606c16fe163c695a992b36c11cdf/six-1.13.0-py2.py3-none-any.whl
Collecting subprocess32==3.5.4 (from localstack)
  Downloading https://files.pythonhosted.org/packages/32/c8/564be4d12629b912ea431f1a50eb8b3b9d00f1a0b1ceff17f266be190007/subprocess32-3.5.4.tar.gz (97kB)
     |????????????????????????????????| 102kB 1.9MB/s
Collecting botocore<1.14.0,>=1.13.43 (from boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/e0/d3/9617609b8e1db654ec34753c43a0538d56c1740a5b4d78690ceb93beca15/botocore-1.13.43-py2.py3-none-any.whl (5.8MB)
     |????????????????????????????????| 5.8MB 2.6MB/s
Collecting s3transfer<0.3.0,>=0.2.0 (from boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/16/8a/1fc3dba0c4923c2a76e1ff0d52b305c44606da63f718d14d3231e21c51b0/s3transfer-0.2.1-py2.py3-none-any.whl (70kB)
     |????????????????????????????????| 71kB 1.5MB/s
Collecting jmespath<1.0.0,>=0.7.1 (from boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/83/94/7179c3832a6d45b266ddb2aac329e101367fbdb11f425f13771d27f225bb/jmespath-0.9.4-py2.py3-none-any.whl
Collecting dnslib==0.9.10 (from localstack-ext>=0.10.51->localstack)
  Downloading https://files.pythonhosted.org/packages/bc/cc/959fea82cc712168f834648f783aa5be2a89e1fed5a4da2a2306bb855a47/dnslib-0.9.10.tar.gz (69kB)
     |????????????????????????????????| 71kB 1.6MB/s
Collecting pyaes==1.6.0 (from localstack-ext>=0.10.51->localstack)
  Downloading https://files.pythonhosted.org/packages/63/31/6768a72cdca5dbd299ae798b690801e6c9c2f018332eec3c5fca79370dba/pyaes-1.6.0.tar.gz
Collecting idna<2.9,>=2.5 (from requests>=2.20.0->localstack)
  Downloading https://files.pythonhosted.org/packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8-py2.py3-none-any.whl (58kB)
     |????????????????????????????????| 61kB 1.9MB/s
Collecting chardet<3.1.0,>=3.0.2 (from requests>=2.20.0->localstack)
  Downloading https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl (133kB)
     |????????????????????????????????| 143kB 2.3MB/s
Collecting certifi>=2017.4.17 (from requests>=2.20.0->localstack)
  Downloading https://files.pythonhosted.org/packages/b9/63/df50cac98ea0d5b006c55a399c3bf1db9da7b5a24de7890bc9cfd5dd9e99/certifi-2019.11.28-py2.py3-none-any.whl (156kB)
     |????????????????????????????????| 163kB 2.1MB/s
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests>=2.20.0->localstack)
  Downloading https://files.pythonhosted.org/packages/b4/40/a9837291310ee1ccc242ceb6ebfd9eb21539649f193a7c8c86ba15b98539/urllib3-1.25.7-py2.py3-none-any.whl (125kB)
     |????????????????????????????????| 133kB 2.2MB/s
Collecting docutils<0.16,>=0.10 (from botocore<1.14.0,>=1.13.43->boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/3a/dc/bf2b15d1fa15a6f7a9e77a61b74ecbbae7258558fcda8ffc9a6638a6b327/docutils-0.15.2-py2-none-any.whl (548kB)
     |????????????????????????????????| 552kB 1.8MB/s
Collecting python-dateutil<2.8.1,>=2.1; python_version >= "2.7" (from botocore<1.14.0,>=1.13.43->boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/41/17/c62faccbfbd163c7f57f3844689e3a78bae1f403648a6afb1d0866d87fbb/python_dateutil-2.8.0-py2.py3-none-any.whl (226kB)
     |????????????????????????????????| 235kB 1.8MB/s
Collecting futures<4.0.0,>=2.2.0; python_version == "2.6" or python_version == "2.7" (from s3transfer<0.3.0,>=0.2.0->boto3>=1.9.71->localstack)
  Downloading https://files.pythonhosted.org/packages/d8/a6/f46ae3f1da0cd4361c344888f59ec2f5785e69c872e175a748ef6071cdb5/futures-3.3.0-py2-none-any.whl
Installing collected packages: docutils, urllib3, six, python-dateutil, jmespath, botocore, futures, s3transfer, boto3, dnspython, docopt, dnslib, pyaes, idna, chardet, certifi, requests, localstack-ext, localstack-client, subprocess32, localstack
  Running setup.py install for docopt ... done
  Running setup.py install for dnslib ... done
  Running setup.py install for pyaes ... done
  Running setup.py install for localstack-ext ... done
  Running setup.py install for localstack-client ... done
  Running setup.py install for subprocess32 ... done
  Running setup.py install for localstack ... done
Successfully installed boto3-1.10.43 botocore-1.13.43 certifi-2019.11.28 chardet-3.0.4 dnslib-0.9.10 dnspython-1.16.0 docopt-0.6.2 docutils-0.15.2 futures-3.3.0 idna-2.8 jmespath-0.9.4 localstack-0.10.6 localstack-client-0.15 localstack-ext-0.10.87 pyaes-1.6.0 python-dat
eutil-2.8.0 requests-2.22.0 s3transfer-0.2.1 six-1.13.0 subprocess32-3.5.4 urllib3-1.25.7
WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.
```
**F:\\*\*\*>localstack start**
```
F:\***>python C:\Python27\Scripts\\localstack start
Starting local dev environment. CTRL-C to quit.
ERROR: environment can only contain strings
```
**F:\\*\*\*>python --version**
```
Python 2.7.17
```
**F:\\*\*\*>localstack --version**
```
F:\***>python C:\Python27\Scripts\\localstack --version
0.10.6
```
**F:\\*\*\*>docker --version**
```
Docker version 19.03.5, build 633a0ea
```

Windows 10 Pro
Version 1903
OS build 18362.535


Discussion:

Thanks for reporting @Alexsey . Can you please enable debug logs and post the output again?
```
python C:\Python27\Scripts\\localstack -d start
```
Btw, the latest pip package should contain a `localstack.bat` file, so if your system path is configured correctly, you should be able to simply type the command `localstack` and Windows should be able to find it.
**F:\\*\*\*>python C:\Python27\Scripts\localstack -d start**
```
Starting local dev environment. CTRL-C to quit.
Traceback (most recent call last):
  File "C:\Python27\Scripts\localstack", line 86, in <module>
    subcommand['function'](argv, args)
  File "C:\Python27\lib\site-packages\localstack\utils\cli.py", line 32, in cmd_infra
    start_infra_in_docker()
  File "C:\Python27\lib\site-packages\localstack\utils\bootstrap.py", line 255, in start_infra_in_docker
    if docker_container_running(container_name):
  File "C:\Python27\lib\site-packages\localstack\utils\bootstrap.py", line 152, in docker_container_running
    container_names = get_docker_container_names()
  File "C:\Python27\lib\site-packages\localstack\utils\bootstrap.py", line 157, in get_docker_container_names
    output = to_str(run("docker ps --format '{{.Names}}'"))
  File "C:\Python27\lib\site-packages\localstack\utils\bootstrap.py", line 449, in run
    output = subprocess.check_output(cmd, shell=True, stderr=stderr, env=env_dict, cwd=cwd)
  File "C:\Python27\lib\site-packages\subprocess32.py", line 337, in check_output
    process = Popen(stdout=PIPE, *popenargs, **kwargs)
  File "C:\Python27\lib\site-packages\subprocess32.py", line 617, in __init__
    restore_signals, start_new_session)
  File "C:\Python27\lib\site-packages\subprocess32.py", line 922, in _execute_child
    startupinfo)
TypeError: environment can only contain strings

ERROR: environment can only contain strings
```
Tell me if there is more I can do to help to reproduce
i have the same issue,
after run 'localstack start'
i have the error:

'uname' is not recognized as an internal or external command,
operable program or batch file.
Starting local dev environment. CTRL-C to quit.
ERROR: environment can only contain strings

Resolving patch:
diff --git a/localstack/services/sqs/sqs_listener.py b/localstack/services/sqs/sqs_listener.py
--- a/localstack/services/sqs/sqs_listener.py
+++ b/localstack/services/sqs/sqs_listener.py
@@ -32,9 +32,13 @@
 
 # list of valid attribute names, and names not supported by the backend (elasticmq)
 VALID_ATTRIBUTE_NAMES = ['DelaySeconds', 'MaximumMessageSize', 'MessageRetentionPeriod',
-                         'ReceiveMessageWaitTimeSeconds', 'RedrivePolicy', 'VisibilityTimeout']
+                         'ReceiveMessageWaitTimeSeconds', 'RedrivePolicy', 'VisibilityTimeout',
+                         'ContentBasedDeduplication', 'KmsMasterKeyId', 'KmsDataKeyReusePeriodSeconds',
+                         'CreatedTimestamp', 'LastModifiedTimestamp', 'FifoQueue',
+                         'ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesNotVisible']
 UNSUPPORTED_ATTRIBUTE_NAMES = [
-    'DelaySeconds', 'MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'RedrivePolicy']
+    'DelaySeconds', 'MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'RedrivePolicy',
+    'ContentBasedDeduplication', 'KmsMasterKeyId', 'KmsDataKeyReusePeriodSeconds']
 
 # maps queue URLs to attributes set via the API
 # TODO: add region as first level in the map
@@ -57,7 +61,10 @@ def forward_request(self, method, path, data, headers):
                     return new_response
             elif action == 'SetQueueAttributes':
                 queue_url = self._queue_url(path, req_data, headers)
-                self._set_queue_attributes(queue_url, req_data)
+                forward_attrs = self._set_queue_attributes(queue_url, req_data)
+                if len(req_data) != len(forward_attrs):
+                    # make sure we only forward the supported attributes to the backend
+                    return self._get_attributes_forward_request(method, path, headers, req_data, forward_attrs)
             elif action == 'DeleteQueue':
                 QUEUE_ATTRIBUTES.pop(self._queue_url(path, req_data, headers), None)
 
@@ -234,7 +241,7 @@ def _format_attributes(self, req_data):
             if key1 not in req_data:
                 break
             key_name = req_data[key1][0]
-            key_value = req_data[key2][0]
+            key_value = (req_data.get(key2) or [''])[0]
             result[key_name] = key_value
         return result
 
@@ -252,6 +259,16 @@ def _format_attributes_names(self, req_data):
             result.add(req_data[key][0])
         return result
 
+    def _get_attributes_forward_request(self, method, path, headers, req_data, forward_attrs):
+        req_data_new = dict([(k, v) for k, v in req_data.items() if not k.startswith('Attribute.')])
+        i = 1
+        for k, v in forward_attrs.items():
+            req_data_new['Attribute.%s.Name' % i] = [k]
+            req_data_new['Attribute.%s.Value' % i] = [v]
+            i += 1
+        data = urlencode(req_data_new, doseq=True)
+        return Request(data=data, headers=headers, method=method)
+
     def _send_message(self, path, data, req_data, headers):
         queue_url = self._queue_url(path, req_data, headers)
         queue_name = queue_url.rpartition('/')[2]
@@ -274,9 +291,11 @@ def _send_message(self, path, data, req_data, headers):
     def _set_queue_attributes(self, queue_url, req_data):
         attrs = self._format_attributes(req_data)
         # select only the attributes in UNSUPPORTED_ATTRIBUTE_NAMES
-        attrs = dict([(k, v) for k, v in attrs.items() if k in UNSUPPORTED_ATTRIBUTE_NAMES])
+        local_attrs = dict([(k, v) for k, v in attrs.items() if k in UNSUPPORTED_ATTRIBUTE_NAMES])
         QUEUE_ATTRIBUTES[queue_url] = QUEUE_ATTRIBUTES.get(queue_url) or {}
-        QUEUE_ATTRIBUTES[queue_url].update(attrs)
+        QUEUE_ATTRIBUTES[queue_url].update(local_attrs)
+        forward_attrs = dict([(k, v) for k, v in attrs.items() if k not in UNSUPPORTED_ATTRIBUTE_NAMES])
+        return forward_attrs
 
     def _add_queue_attributes(self, path, req_data, content_str, headers):
         flags = re.MULTILINE | re.DOTALL
diff --git a/localstack/utils/bootstrap.py b/localstack/utils/bootstrap.py
--- a/localstack/utils/bootstrap.py
+++ b/localstack/utils/bootstrap.py
@@ -436,6 +436,7 @@ def run(cmd, print_error=True, asynchronous=False, stdin=False,
     env_dict = os.environ.copy() if inherit_env else {}
     if env_vars:
         env_dict.update(env_vars)
+    env_dict = dict([(k, to_str(str(v))) for k, v in env_dict.items()])
 
     if tty:
         asynchronous = True


Test patch: