codedeploy install/uninstall: TypeError (bytes vs str) crashes when agent service not found
- Dominant language
- Python
- Stars
- 17.3k
- Forks
- 4.6k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 21
Description
## Summary
`aws deploy install` / `aws deploy uninstall` (the on-premises CodeDeploy agent installer) crashes with an unhandled `TypeError` instead of gracefully handling the case where the `codedeployagent`/`codedeploy-agent` service does not exist yet — which is exactly the situation on a fresh host doing its first install.
## Root cause
`awscli/customizations/codedeploy/systems.py` creates several `subprocess.Popen(...)` calls without `text=True`/`universal_newlines=True`:
```python
process = subprocess.Popen(
['service', 'codedeploy-agent', 'stop'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
(output, error) = process.communicate()
if process.returncode != 0 and params.not_found_msg not in error:
raise RuntimeError(...)
```
Because `text=True` is omitted, `process.communicate()` returns `bytes`, but the code checks membership of a `str` literal (`params.not_found_msg`, or the `not_found`/`"Running"` literals in the `Windows` class) against that `bytes` object. In Python 3, `"str" in b"bytes"` raises `TypeError: a bytes-like object is required, not 'str'` — it does not evaluate to `False`.
Affected locations:
- `Windows.install` (~L75): `if process.returncode != 0 and not_found not in error:`
- `Windows.install` (~L108): `if "Running" not in output:`
- `Windows.uninstall` (same pattern as install)
- `Linux._stop_agent` (~L208, used by `Ubuntu`/`RHEL` `install`/`uninstall`): `if process.returncode != 0 and params.not_found_msg not in error:`
## Reproduction
Verified by executing the real, unmodified `Linux._stop_agent` method against a stub `service` binary that reproduces the "service not registered yet" condition (exit code 1, stderr containing the expected "not found" message):
```python
import sys
from awscli.customizations.codedeploy.systems import Linux
class Params(dict):
def __getattr__(self, k):
return self[k]
linux = Linux.__new__(Linux)
params = Params()
params['not_found_msg'] = 'codedeploy-agent: unrecognized service'
linux._stop_agent(params)
```
with a `service` script on `PATH` that does:
```bash
#!/bin/bash
echo "service: unrecognized service" 1>&2
exit 1
```
Result:
```
TypeError: a bytes-like object is required, not 'str'
```
instead of the intended graceful pass-through (or the documented `RuntimeError` when the failure is for a different reason).
## Impact
This affects essentially every fresh `aws deploy install` and every `aws deploy uninstall` on Windows, Ubuntu, and RHEL on-premises instances — i.e. exactly the first-run scenario the `not_found`/`not_found_msg` check was written to tolerate. Instead of installing successfully or uninstalling cleanly, the command crashes with an unrelated `TypeError` traceback.
## Suggested fix
Add `text=True` (or `universal_newlines=True`) to each `subprocess.Popen(...)` call in `awscli/customizations/codedeploy/systems.py` so `communicate()` returns `str`, matching what the existing string-membership checks assume.
## Environment
Reviewed against the current `aws-cli` source. This is aws-cli-specific customization code (not vendored botocore).
Contributor guide
Research direction
Start in awscli/customizations/codedeploy/systems.py by inspecting Windows.install, Windows.uninstall, and Linux._stop_agent, then reproduce the fresh-service case with the stub service command described in the issue. Ensure the install and uninstall paths handle missing services without a TypeError while still raising RuntimeError for other failures.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100