From 801f215bd2cd5341d63b5dd91298d23b11dc3553 Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Tue, 26 May 2015 14:36:14 -0400 Subject: docker-storage role added --- filter_plugins/oo_filters.py | 376 +++++++++++++++++---------------- roles/docker/files/enter-container.sh | 13 -- roles/docker/handlers/main.yml | 4 + roles/docker/tasks/main.yml | 9 +- roles/docker_storage/README.md | 39 ++++ roles/docker_storage/defaults/main.yml | 1 + roles/docker_storage/handlers/main.yml | 1 + roles/docker_storage/meta/main.yml | 9 + roles/docker_storage/tasks/main.yml | 37 ++++ roles/docker_storage/vars/main.yml | 1 + 10 files changed, 292 insertions(+), 198 deletions(-) delete mode 100755 roles/docker/files/enter-container.sh create mode 100644 roles/docker/handlers/main.yml create mode 100644 roles/docker_storage/README.md create mode 100644 roles/docker_storage/defaults/main.yml create mode 100644 roles/docker_storage/handlers/main.yml create mode 100644 roles/docker_storage/meta/main.yml create mode 100644 roles/docker_storage/tasks/main.yml create mode 100644 roles/docker_storage/vars/main.yml diff --git a/filter_plugins/oo_filters.py b/filter_plugins/oo_filters.py index 097038450..33d5e6cc3 100644 --- a/filter_plugins/oo_filters.py +++ b/filter_plugins/oo_filters.py @@ -9,188 +9,210 @@ from ansible import errors from operator import itemgetter import pdb -def oo_pdb(arg): - ''' This pops you into a pdb instance where arg is the data passed in - from the filter. - Ex: "{{ hostvars | oo_pdb }}" - ''' - pdb.set_trace() - return arg - -def oo_len(arg): - ''' This returns the length of the argument - Ex: "{{ hostvars | oo_len }}" - ''' - return len(arg) - -def get_attr(data, attribute=None): - ''' This looks up dictionary attributes of the form a.b.c and returns - the value. - Ex: data = {'a': {'b': {'c': 5}}} - attribute = "a.b.c" - returns 5 - ''' - if not attribute: - raise errors.AnsibleFilterError("|failed expects attribute to be set") - - ptr = data - for attr in attribute.split('.'): - ptr = ptr[attr] - - return ptr - -def oo_flatten(data): - ''' This filter plugin will flatten a list of lists - ''' - if not issubclass(type(data), list): - raise errors.AnsibleFilterError("|failed expects to flatten a List") - - return [item for sublist in data for item in sublist] - - -def oo_collect(data, attribute=None, filters=None): - ''' This takes a list of dict and collects all attributes specified into a - list If filter is specified then we will include all items that match - _ALL_ of filters. - Ex: data = [ {'a':1, 'b':5, 'z': 'z'}, # True, return - {'a':2, 'z': 'z'}, # True, return - {'a':3, 'z': 'z'}, # True, return - {'a':4, 'z': 'b'}, # FAILED, obj['z'] != obj['z'] - ] - attribute = 'a' - filters = {'z': 'z'} - returns [1, 2, 3] - ''' - if not issubclass(type(data), list): - raise errors.AnsibleFilterError("|failed expects to filter on a List") - - if not attribute: - raise errors.AnsibleFilterError("|failed expects attribute to be set") - - if filters is not None: - if not issubclass(type(filters), dict): - raise errors.AnsibleFilterError("|fialed expects filter to be a" - " dict") - retval = [get_attr(d, attribute) for d in data if ( - all([d[key] == filters[key] for key in filters]))] - else: - retval = [get_attr(d, attribute) for d in data] - - return retval - -def oo_select_keys(data, keys): - ''' This returns a list, which contains the value portions for the keys - Ex: data = { 'a':1, 'b':2, 'c':3 } - keys = ['a', 'c'] - returns [1, 3] - ''' - - if not issubclass(type(data), dict): - raise errors.AnsibleFilterError("|failed expects to filter on a dict") - - if not issubclass(type(keys), list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - - # Gather up the values for the list of keys passed in - retval = [data[key] for key in keys] - - return retval - -def oo_prepend_strings_in_list(data, prepend): - ''' This takes a list of strings and prepends a string to each item in the - list - Ex: data = ['cart', 'tree'] - prepend = 'apple-' - returns ['apple-cart', 'apple-tree'] - ''' - if not issubclass(type(data), list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - if not all(isinstance(x, basestring) for x in data): - raise errors.AnsibleFilterError("|failed expects first param is a list" - " of strings") - retval = [prepend + s for s in data] - return retval - -def oo_ami_selector(data, image_name): - ''' This takes a list of amis and an image name and attempts to return - the latest ami. - ''' - if not issubclass(type(data), list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - - if not data: - return None - else: - if image_name is None or not image_name.endswith('_*'): - ami = sorted(data, key=itemgetter('name'), reverse=True)[0] - return ami['ami_id'] + +class FilterModule(object): + ''' Custom ansible filters ''' + + @staticmethod + def oo_pdb(arg): + ''' This pops you into a pdb instance where arg is the data passed in + from the filter. + Ex: "{{ hostvars | oo_pdb }}" + ''' + pdb.set_trace() + return arg + + @staticmethod + def oo_len(arg): + ''' This returns the length of the argument + Ex: "{{ hostvars | oo_len }}" + ''' + return len(arg) + + @staticmethod + def get_attr(data, attribute=None): + ''' This looks up dictionary attributes of the form a.b.c and returns + the value. + Ex: data = {'a': {'b': {'c': 5}}} + attribute = "a.b.c" + returns 5 + ''' + if not attribute: + raise errors.AnsibleFilterError("|failed expects attribute to be set") + + ptr = data + for attr in attribute.split('.'): + ptr = ptr[attr] + + return ptr + + @staticmethod + def oo_flatten(data): + ''' This filter plugin will flatten a list of lists + ''' + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects to flatten a List") + + return [item for sublist in data for item in sublist] + + + @staticmethod + def oo_collect(data, attribute=None, filters=None): + ''' This takes a list of dict and collects all attributes specified into a + list If filter is specified then we will include all items that match + _ALL_ of filters. + Ex: data = [ {'a':1, 'b':5, 'z': 'z'}, # True, return + {'a':2, 'z': 'z'}, # True, return + {'a':3, 'z': 'z'}, # True, return + {'a':4, 'z': 'b'}, # FAILED, obj['z'] != obj['z'] + ] + attribute = 'a' + filters = {'z': 'z'} + returns [1, 2, 3] + ''' + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects to filter on a List") + + if not attribute: + raise errors.AnsibleFilterError("|failed expects attribute to be set") + + if filters is not None: + if not issubclass(type(filters), dict): + raise errors.AnsibleFilterError("|fialed expects filter to be a" + " dict") + retval = [FilterModule.get_attr(d, attribute) for d in data if ( + all([d[key] == filters[key] for key in filters]))] else: - ami_info = [(ami, ami['name'].split('_')[-1]) for ami in data] - ami = sorted(ami_info, key=itemgetter(1), reverse=True)[0][0] - return ami['ami_id'] - -def oo_ec2_volume_definition(data, host_type, docker_ephemeral=False): - ''' This takes a dictionary of volume definitions and returns a valid ec2 - volume definition based on the host_type and the values in the - dictionary. - The dictionary should look similar to this: - { 'master': - { 'root': - { 'volume_size': 10, 'device_type': 'gp2', - 'iops': 500 - } - }, - 'node': - { 'root': - { 'volume_size': 10, 'device_type': 'io1', - 'iops': 1000 + retval = [FilterModule.get_attr(d, attribute) for d in data] + + return retval + + @staticmethod + def oo_select_keys(data, keys): + ''' This returns a list, which contains the value portions for the keys + Ex: data = { 'a':1, 'b':2, 'c':3 } + keys = ['a', 'c'] + returns [1, 3] + ''' + + if not issubclass(type(data), dict): + raise errors.AnsibleFilterError("|failed expects to filter on a dict") + + if not issubclass(type(keys), list): + raise errors.AnsibleFilterError("|failed expects first param is a list") + + # Gather up the values for the list of keys passed in + retval = [data[key] for key in keys] + + return retval + + @staticmethod + def oo_prepend_strings_in_list(data, prepend): + ''' This takes a list of strings and prepends a string to each item in the + list + Ex: data = ['cart', 'tree'] + prepend = 'apple-' + returns ['apple-cart', 'apple-tree'] + ''' + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects first param is a list") + if not all(isinstance(x, basestring) for x in data): + raise errors.AnsibleFilterError("|failed expects first param is a list" + " of strings") + retval = [prepend + s for s in data] + return retval + + @staticmethod + def oo_combine_key_value(data, joiner='='): + '''Take a list of dict in the form of { 'key': 'value'} and + arrange them as a list of strings ['key=value'] + ''' + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects first param is a list") + + rval = [] + for item in data: + rval.append("%s%s%s" % (item['key'], joiner, item['value'])) + + return rval + + @staticmethod + def oo_ami_selector(data, image_name): + ''' This takes a list of amis and an image name and attempts to return + the latest ami. + ''' + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects first param is a list") + + if not data: + return None + else: + if image_name is None or not image_name.endswith('_*'): + ami = sorted(data, key=itemgetter('name'), reverse=True)[0] + return ami['ami_id'] + else: + ami_info = [(ami, ami['name'].split('_')[-1]) for ami in data] + ami = sorted(ami_info, key=itemgetter(1), reverse=True)[0][0] + return ami['ami_id'] + + @staticmethod + def oo_ec2_volume_definition(data, host_type, docker_ephemeral=False): + ''' This takes a dictionary of volume definitions and returns a valid ec2 + volume definition based on the host_type and the values in the + dictionary. + The dictionary should look similar to this: + { 'master': + { 'root': + { 'volume_size': 10, 'device_type': 'gp2', + 'iops': 500 + } }, - 'docker': - { 'volume_size': 40, 'device_type': 'gp2', - 'iops': 500, 'ephemeral': 'true' + 'node': + { 'root': + { 'volume_size': 10, 'device_type': 'io1', + 'iops': 1000 + }, + 'docker': + { 'volume_size': 40, 'device_type': 'gp2', + 'iops': 500, 'ephemeral': 'true' + } } } - } - ''' - if not issubclass(type(data), dict): - raise errors.AnsibleFilterError("|failed expects first param is a dict") - if host_type not in ['master', 'node']: - raise errors.AnsibleFilterError("|failed expects either master or node" - " host type") - - root_vol = data[host_type]['root'] - root_vol['device_name'] = '/dev/sda1' - root_vol['delete_on_termination'] = True - if root_vol['device_type'] != 'io1': - root_vol.pop('iops', None) - if host_type == 'node': - docker_vol = data[host_type]['docker'] - docker_vol['device_name'] = '/dev/xvdb' - docker_vol['delete_on_termination'] = True - if docker_vol['device_type'] != 'io1': - docker_vol.pop('iops', None) - if docker_ephemeral: - docker_vol.pop('device_type', None) - docker_vol.pop('delete_on_termination', None) - docker_vol['ephemeral'] = 'ephemeral0' - return [root_vol, docker_vol] - return [root_vol] - -# disabling pylint checks for too-few-public-methods and no-self-use since we -# need to expose a FilterModule object that has a filters method that returns -# a mapping of filter names to methods. -# pylint: disable=too-few-public-methods, no-self-use -class FilterModule(object): - ''' FilterModule ''' + ''' + if not issubclass(type(data), dict): + raise errors.AnsibleFilterError("|failed expects first param is a dict") + if host_type not in ['master', 'node']: + raise errors.AnsibleFilterError("|failed expects either master or node" + " host type") + + root_vol = data[host_type]['root'] + root_vol['device_name'] = '/dev/sda1' + root_vol['delete_on_termination'] = True + if root_vol['device_type'] != 'io1': + root_vol.pop('iops', None) + if host_type == 'node': + docker_vol = data[host_type]['docker'] + docker_vol['device_name'] = '/dev/xvdb' + docker_vol['delete_on_termination'] = True + if docker_vol['device_type'] != 'io1': + docker_vol.pop('iops', None) + if docker_ephemeral: + docker_vol.pop('device_type', None) + docker_vol.pop('delete_on_termination', None) + docker_vol['ephemeral'] = 'ephemeral0' + return [root_vol, docker_vol] + return [root_vol] + def filters(self): ''' returns a mapping of filters to methods ''' return { - "oo_select_keys": oo_select_keys, - "oo_collect": oo_collect, - "oo_flatten": oo_flatten, - "oo_len": oo_len, - "oo_pdb": oo_pdb, - "oo_prepend_strings_in_list": oo_prepend_strings_in_list, - "oo_ami_selector": oo_ami_selector, - "oo_ec2_volume_definition": oo_ec2_volume_definition + "oo_select_keys": self.oo_select_keys, + "oo_collect": self.oo_collect, + "oo_flatten": self.oo_flatten, + "oo_len": self.oo_len, + "oo_pdb": self.oo_pdb, + "oo_prepend_strings_in_list": self.oo_prepend_strings_in_list, + "oo_ami_selector": self.oo_ami_selector, + "oo_ec2_volume_definition": self.oo_ec2_volume_definition, + "oo_combine_key_value": self.oo_combine_key_value, } diff --git a/roles/docker/files/enter-container.sh b/roles/docker/files/enter-container.sh deleted file mode 100755 index 7cf5b8d83..000000000 --- a/roles/docker/files/enter-container.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -if [ $# -ne 1 ] -then - echo - echo "Usage: $(basename $0) " - echo - exit 1 -fi - -PID=$(docker inspect --format '{{.State.Pid}}' $1) - -nsenter --target $PID --mount --uts --ipc --net --pid diff --git a/roles/docker/handlers/main.yml b/roles/docker/handlers/main.yml new file mode 100644 index 000000000..eca7419c1 --- /dev/null +++ b/roles/docker/handlers/main.yml @@ -0,0 +1,4 @@ +--- + +- name: restart docker + service: name=docker state=restarted diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index ca700db17..96949230d 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -1,15 +1,8 @@ --- # tasks file for docker - name: Install docker - yum: pkg=docker-io + yum: pkg=docker - name: enable and start the docker service service: name=docker enabled=yes state=started -- copy: src=enter-container.sh dest=/usr/local/bin/enter-container.sh mode=0755 - -# From the origin rpm there exists instructions on how to -# setup origin properly. The following steps come from there -- name: Change root to be in the Docker group - user: name=root groups=dockerroot append=yes - diff --git a/roles/docker_storage/README.md b/roles/docker_storage/README.md new file mode 100644 index 000000000..0d8f31afc --- /dev/null +++ b/roles/docker_storage/README.md @@ -0,0 +1,39 @@ +docker_storage +========= + +Configure docker_storage options +------------ + +None + +Role Variables +-------------- + +None + +Dependencies +------------ + +None + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + + - hosts: servers + roles: + - { role/docker_storage: + - key: df.fs + value: xfs + } + +License +------- + +ASL 2.0 + +Author Information +------------------ + +Openshift operations, Red Hat, Inc diff --git a/roles/docker_storage/defaults/main.yml b/roles/docker_storage/defaults/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/docker_storage/defaults/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/docker_storage/handlers/main.yml b/roles/docker_storage/handlers/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/docker_storage/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/docker_storage/meta/main.yml b/roles/docker_storage/meta/main.yml new file mode 100644 index 000000000..a5d51cd3a --- /dev/null +++ b/roles/docker_storage/meta/main.yml @@ -0,0 +1,9 @@ +--- +galaxy_info: + author: Openshift + description: Setup docker_storage options + company: Red Hat, Inc + license: ASL 2.0 + min_ansible_version: 1.2 +dependencies: +- docker diff --git a/roles/docker_storage/tasks/main.yml b/roles/docker_storage/tasks/main.yml new file mode 100644 index 000000000..48a3fc208 --- /dev/null +++ b/roles/docker_storage/tasks/main.yml @@ -0,0 +1,37 @@ +--- +- lvg: + pvs: "{{ dst_device }}" + vg: "{{ dst_vg }}" + register: dst_lvg + +- lvol: + lv: data + vg: "{{ dst_vg }}" + size: 95%VG + register: dst_lvol_data + +- lvol: + lv: metadata + vg: "{{ dst_vg }}" + size: 5%VG + register: dst_lvol_metadata + + +- name: Update docker_storage options + lineinfile: + dest: /etc/sysconfig/docker-storage + backrefs: yes + regexp: "^(DOCKER_STORAGE_OPTIONS=)" + line: '\1 --storage-opt {{ dst_options | oo_combine_key_value("=") | join(" --storage-opt ") }}' + when: dst_options is defined and dst_options | length > 0 + register: dst_config + + +- name: Reload systemd units + command: systemctl daemon-reload + notify: + - restart docker + when: dst_config | changed or + dst_lvg | changed or + dst_lvol_data | changed or + dst_lvol_metadata | changed diff --git a/roles/docker_storage/vars/main.yml b/roles/docker_storage/vars/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/docker_storage/vars/main.yml @@ -0,0 +1 @@ +--- -- cgit v1.2.3