Skip to content

Commit

Permalink
Added support for repairing issues with specific Docker upgrades (#5)
Browse files Browse the repository at this point in the history
* Added (optional) support for repairing some issues that occur on specific Docker upgrades.
* Added automated tests that can be run in Vagrant, for this and other things.
  • Loading branch information
ostacey authored Sep 12, 2016
1 parent 47db57c commit a1fa5be
Show file tree
Hide file tree
Showing 24 changed files with 815 additions and 52 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tests/build
tests/.vagrant
11 changes: 11 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
Version 2.1:
- Change default Docker version to 1.11.2, was 1.5.0
- Attempt to handle data volume loss when we update from pre-1.10 to post-1.10.
See: https://github.com/docker/docker/issues/20079
- Attempt to handle missing volume symlinks when we upgrade pre-1.9 data volumes
to a post-1.9.x version.
- Add "docker_attempt_upgrade_fixes" configuration variable. This defaults to False;
the upgrade fixes mentioned above won't be attempted unless it is set to True.
- Added automated tests in the "tests" directory - if you have Vagrant installed, they
can be run by "cd tests ; ./run_tests.sh".

Version 2.0:
- Port to github
45 changes: 30 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,47 @@ to manage which version of Docker we install. Because of interdepencies between
version and software that we install (especially `docker-py`), we have to be careful about
Docker versions.

- Our initial deploys used a fixed version of LXC Docker, pinned at `1.5.0`
- Our newer deploy will still use a pinned version Docker Engine, but will be able to specify
- Our initial deploys used a fixed version of LXC Docker, pinned at `1.5.0`
- Our newer deploy will still use a pinned version Docker Engine, but will be able to specify
their own versions (e.g. `1.8.1`)

Upgrade Support
---------------

Role Variables
--------------
Some Docker Engine upgrade paths have known issues. There's code in this role that attempts to
resolve those issues, with minimum disruption, if those upgrade paths are encountered. The
intention is to not require containers to be recreated.

The `docker_version` variable controls what version of Docker is installed.
This code isn't intended to catch everything; an attempt has been made to make it reasonable and
non-harmful, but it hasn't been tested for all possible upgrade paths, nor with features like
non-local storage drivers. With that in mind, this behavior is optional and is disabled by default.

- The default `docker_version` is `1.5.0` (for historical reasons). If select, LXC Docker will be used.
- Otherwise, the stated version of Docker Engine will be used (if available).
The issues we attempt to resolve are documented in the "repair_docker_data_volumes" module.


Testing
-------
Role Variables
--------------

There are known incompatibilities between some Docker versions and some versions of `docker-py`,
especially between LXC Docker `1.5.0` and `docker-py>1.1.0`. Using this combination will
result in Python errors along the lines of:
- `docker_version` : this variable controls the version of Docker that is installed. Required.
If version `1.5.0` is selected, LXC Docker will be used; otherwise the stated version of
Docker Engine will be installed (if available).
- `docker_attempt_upgrade_fixes` : False by default. If True, the fixes described in "Upgrade
Support" will be attempted
- `cgroup_lite_pkg_state` : When installing on an Ubuntu 13.10 host, the role will install the
`cgroup-lite` package to provide the required cgroups support. This variable can be set to
`latest` - the default - or to `present`. In the former case, the package will be updated, if
necessary, when the role is run. In the latter, the package will only be added if it is not
present.
- `kernel_pkg_state` : For 13.04+, this role will install a `linux-image-extra-<version>`
package. This parameter works the same way as `cgroup_lite_package_state`, except controlling
this package.

client and server don't have same version (client : 1.19, server: 1.17)

Fortunately, newer versions of Docker Engine with both newer and older versions of `docker-py`
appear to be compatible. A `testing.yml` playbook is provided for reference.
Testing
-------

There's a directory "tests" with some Ansible playbooks that can be used for verifying role
behavior. See tests/TESTS.md for more information.

License
-------
Expand Down
6 changes: 5 additions & 1 deletion defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
---
docker_version: 1.5.0

kernel_pkg_state: latest
cgroup_lite_pkg_state: latest
ssh_port: 22

docker_role_apt_cache_valid_time: 7200

docker_attempt_upgrade_fixes: False
2 changes: 1 addition & 1 deletion handlers/main.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
# handlers file for docker.ubuntu

67 changes: 67 additions & 0 deletions library/collect_container_configs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python2.7

import json
import os
import os.path

DOCUMENTATION = '''
---
module: collect_container_configs
short_description: collects container configuration data
description:
- when run, this module collects the contents of container configuration files for
all current containers
- this can be run before an upgrade to store information that would be used after
an upgrade
- this is returned as a single string containing parsable JSON.
'''


CONTAINER_ROOT_DIR = '/var/lib/docker/containers'


CONFIG_FILENAME_OPTIONS = [
('config.v3.json', 3),
('config.v2.json', 2),
('config.json', 1)
]


def main():
module = AnsibleModule(
argument_spec=dict(),
supports_check_mode=True)

configs = {}
config_versions = {}

if os.path.isdir(CONTAINER_ROOT_DIR):
for container in os.listdir(CONTAINER_ROOT_DIR):
container_path = os.path.join(CONTAINER_ROOT_DIR, container)
if not os.path.isdir(container_path):
# we only expect directories here. Ignore the unexpected
continue

for basename, version in CONFIG_FILENAME_OPTIONS:
config_path = os.path.join(container_path, basename)
if os.path.isfile(config_path):
break
else:
# no config file was found
continue

with file(config_path, 'r') as f:
config = json.load(f)

configs[container] = config
config_versions[container] = version

module.exit_json(
changed=False,
configs=configs,
config_versions=config_versions)


from ansible.module_utils.basic import *
if __name__ == '__main__':
main()
Loading

0 comments on commit a1fa5be

Please sign in to comment.