#!/usr/bin/python # -*- coding: utf-8 -*- DOCUMENTATION = """ --- module: lilik_container short_description: Manage LXC Containers - Lilik style version_added: 2.1.0 description: - Management of LXC containers options: name: description: - Name of a container required: true backing_store: choices: - dir - lvm - loop - btrfs - overlayfs - zfs description - Backend storage type for the container. required: false default: lvm config: description: - Path to the LXC configuration file required: false default: /etc/lxc/default.conf template: description: - Name of the template to use within an LXC create. required: false default: debian template_options: description: - Template options when building the container. required: false default: --release jessie --packages=ssh,python lv_name: description: - Name of the logical volume, defaults to the container name. default: "vm_{{$CONTAINER_NAME}}" required: false vg_name: description: - If Backend store is lvm, specify the name of the volume group. default: newsysvg required: false fs_type: description: - Create fstype TYPE. default: ext4 required: false fs_size: description: - File system Size. default: 5G required: false container_command: description: - Run a command within a container. required: false state: choices: - started - stopped - restarted - absent - frozen description: - Define the state of a container. required: false default: started requirements: - 'liblxc1 >= 1.1.5 # OS package' - 'python >= 2.6 # OS package' - 'lxc-python2 >= 0.1 #PIP package from https://github.com/lxc/python2-lxc' """ from ansible.module_utils.basic import * class LilikContainer(object): """ A generic lxc container manipulation object based on python-lxc """ def __init__(self, module): self.module = module self.state = module.params['state'] self.name = module.params['name'] self.template = module.params['template'] self.template_options = module.params['template_options'] self.config = module.params['config'] self.backing_store = module.params['backing_store'] # handle default name self.lvname = module.params.get('lv_name', 'vm_%s' % module.params['name']) self.vgname = module.params['vg_name'] self.fstype = module.params['fs_type'] self.fssize = module.params['fs_size'] def create_container(self): """ Create a lxc.Container object as specified in the playbook, use it to create a lxc container and returns the reference """ container_options = { 'bdev': self.backing_store, 'config': self.config, 'lvname': self.lvname, 'vgname': self.vgname, 'fstype': self.fstype, 'fssize': self.fssize, 'bdev' : self.backing_store, } try: import lxc except ImportError: self.module.fail_json(changed=False, msg='Error importing lxc') container = lxc.Container(name = self.name) # TODO: python2-lxc does not like bdevtype but python-lxc does return container.create( template = self.template, args = container_options, # bdevtype = self.backing_store ) def main(): module = AnsibleModule( argument_spec = dict( backing_store = dict( default='lvm', choices=['dir', 'lvm', 'loop', 'btrsf', 'overlayfs', 'zfs',], type='str', ), config = dict( required=False, default='/etc/lxc/default.conf', ), container_command = dict( required=False, type='str', default='', ), fs_size = dict( required=False, default='5G', type='str', ), fs_type = dict( required=False, default='ext4', type='str', ), lv_name = dict( type='str', ), name = dict( required=True, type='str', ), state = dict( default='started', choices=['started', 'stopped', 'restarted', 'absent', 'frozen'], type='str', ), template = dict( required=False, default='debian', type='str', ), template_options = dict( required=False, default='--release jessie --packages=ssh,python', type='str', ), vg_name = dict( required=False, default='newsysvg', type='str', ), ) ) try: import lxc except ImportError: module.fail_json(changed=False, msg='liblxc is required for this module to work') lilik_container = LilikContainer(module) result = {} result['name'] = lilik_container.name result['state'] = lilik_container.state if lilik_container.state == 'absent': # destroy the container if lilik_container.destoy(): module.exit_json(changed=True) # TODO: remove redundant test # test wether the container is absent or not if lilik_container.name in lxc.list_containers(): module.fail_json(changed=False) # the container has been removed else: module.exit_json(changed=True) # end TODO: remove redundant test elif lilik_container.state in ['started', 'stopped', 'restarted', 'frozen']: # the container exists, just set the state as required if lilik_container.name in lxc.list_containers(): container_actions_from_state = { 'started': lilik_container.start, 'stopped': lilik_container.stop, 'restarted': lilik_container.restart, 'frozen': lilik_container.freeze, } # selected action action = container_actions.get(container.state) if action(): module.exit_json(changed=True) else: module.exit_json(changed=False) # the container does not exists, create it else: try: new_container = lilik_container.create_container() module.exit_json(changed=True) except Exception as e: module.fail_json( changed=False, msg='An excption was raised while creating the container', exception_message=str(e), ) if __name__ == '__main__': main()