A pure Python implementation of the lxc_container ansible module
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
7.3 KiB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. DOCUMENTATION = """
  4. ---
  5. module: lilik_container
  6. short_description: Manage LXC Containers - Lilik style
  7. version_added: 2.1.0
  8. description:
  9. - Management of LXC containers
  10. options:
  11. name:
  12. description:
  13. - Name of a container
  14. required: true
  15. backing_store:
  16. choices:
  17. - dir
  18. - lvm
  19. - loop
  20. - btrfs
  21. - overlayfs
  22. - zfs
  23. description
  24. - Backend storage type for the container.
  25. required: false
  26. default: lvm
  27. config:
  28. description:
  29. - Path to the LXC configuration file
  30. required: false
  31. default: /etc/lxc/default.conf
  32. template:
  33. description:
  34. - Name of the template to use within an LXC create.
  35. required: false
  36. default: debian
  37. template_options:
  38. description:
  39. - Template options when building the container.
  40. required: false
  41. default: --release jessie
  42. lv_name:
  43. description:
  44. - Name of the logical volume, defaults to the container name.
  45. default: "vm_{{$CONTAINER_NAME}}"
  46. required: false
  47. vg_name:
  48. description:
  49. - If Backend store is lvm, specify the name of the volume group.
  50. default: sysvg
  51. required: false
  52. fs_type:
  53. description:
  54. - Create fstype TYPE.
  55. default: ext4
  56. required: false
  57. fs_size:
  58. description:
  59. - File system Size.
  60. default: 5G
  61. required: false
  62. container_command:
  63. description:
  64. - Run a command within a container.
  65. required: false
  66. default: apt-get update; apt-get install python
  67. state:
  68. choices:
  69. - started
  70. - stopped
  71. - restarted
  72. - absent
  73. - frozen
  74. description:
  75. - Define the state of a container.
  76. required: false
  77. default: started
  78. requirements:
  79. - 'liblxc1 >= 1.1.5 # OS package'
  80. - 'python >= 2.6 # OS package'
  81. - 'lxc-python2 >= 0.1 #PIP package from https://github.com/lxc/python2-lxc'
  82. """
  83. from ansible.module_utils.basic import *
  84. class LilikContainer(object):
  85. """
  86. A generic lxc container manipulation object based on python-lxc
  87. """
  88. def __init__(self, module):
  89. self.module = module
  90. self.state = module.params['state']
  91. self.name = module.params['name']
  92. self.template = module.params['template']
  93. self.config = module.params['config']
  94. self.backing_store = module.params['backing_store']
  95. # handle default name
  96. self.lvname = module.params.get('lv_name', 'vm_%s' % module.params['name'])
  97. self.vgname = module.params['vg_name']
  98. self.fstype = module.params['fs_type']
  99. self.fssize = module.params['fs_size']
  100. def create_container(self):
  101. """
  102. Create a lxc.Container object as specified in the playbook, use it
  103. to create a lxc container and returns the reference
  104. """
  105. container_options = {
  106. 'bdev': self.backing_store,
  107. 'config': self.config,
  108. 'lvname': self.lvname,
  109. 'vgname': self.vgname,
  110. 'fstype': self.fstype,
  111. 'fssize': self.fssize,
  112. 'bdev' : self.backing_store,
  113. }
  114. try:
  115. import lxc
  116. except ImportError:
  117. self.module.fail_json(changed=False, msg='Error importing lxc')
  118. container = lxc.Container(name = self.name)
  119. # TODO: python2-lxc does not like bdevtype but python-lxc does
  120. return container.create(
  121. template = self.template,
  122. args = container_options,
  123. # bdevtype = self.backing_store
  124. )
  125. def main():
  126. module = AnsibleModule(
  127. argument_spec = dict(
  128. backing_store = dict(
  129. default='lvm',
  130. choices=['dir', 'lvm', 'loop', 'btrsf', 'overlayfs', 'zfs',],
  131. type='str',
  132. ),
  133. config = dict(
  134. required=False,
  135. default='/etc/lxc/default.conf',
  136. ),
  137. container_command = dict(
  138. type='str',
  139. default='apt-get update; apt-get install python',
  140. ),
  141. fs_size = dict(
  142. required=False,
  143. default='5G',
  144. type='str',
  145. ),
  146. fs_type = dict(
  147. required=False,
  148. default='ext4',
  149. type='str',
  150. ),
  151. lv_name = dict(
  152. type='str',
  153. ),
  154. name = dict(
  155. required=True,
  156. type='str',
  157. ),
  158. state = dict(
  159. default='started',
  160. choices=['started', 'stopped', 'restarted', 'absent', 'frozen'],
  161. type='str',
  162. ),
  163. template = dict(
  164. required=False,
  165. default='debian',
  166. type='str',
  167. ),
  168. template_options = dict(required=False),
  169. vg_name = dict(
  170. required=False,
  171. default='sysvf',
  172. type='str',
  173. ),
  174. )
  175. )
  176. try:
  177. import lxc
  178. except ImportError:
  179. module.fail_json(changed=False, msg='liblxc is required for this module to work')
  180. lilik_container = LilikContainer(module)
  181. result = {}
  182. result['name'] = lilik_container.name
  183. result['state'] = lilik_container.state
  184. if lilik_container.state == 'absent':
  185. # destroy the container
  186. if lilik_container.destoy():
  187. module.exit_json(changed=True)
  188. # TODO: remove redundant test
  189. # test wether the container is absent or not
  190. if lilik_container.name in lxc.list_containers():
  191. module.fail_json(changed=False)
  192. # the container has been removed
  193. else:
  194. module.exit_json(changed=True)
  195. # end TODO: remove redundant test
  196. elif lilik_container.state in ['started', 'stopped', 'restarted', 'frozen']:
  197. # the container exists, just set the state as required
  198. if lilik_container.name in lxc.list_containers():
  199. container_actions_from_state = {
  200. 'started': lilik_container.start,
  201. 'stopped': lilik_container.stop,
  202. 'restarted': lilik_container.restart,
  203. 'frozen': lilik_container.freeze,
  204. }
  205. # selected action
  206. action = container_actions.get(container.state)
  207. if action():
  208. module.exit_json(changed=True)
  209. else:
  210. module.exit_json(changed=False)
  211. # the container does not exists, create it
  212. else:
  213. try:
  214. new_container = lilik_container.create_container()
  215. module.exit_json(changed=True)
  216. except Exception as e:
  217. module.fail_json(
  218. changed=False,
  219. msg='An excption was raised while creating the container',
  220. exception_message=str(e),
  221. )
  222. if __name__ == '__main__':
  223. main()