From fd0c21df27da5c952ef71b69fadc1d74cb052eea Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Wed, 13 May 2015 21:20:05 -0500 Subject: [PATCH] Updated lxc module to remove the clone state The clone state was removed in favor of making the module more declarative. This change was done in response to review in PR #328 from @bcoca. In the commit new examples were created on how this feature works. --- cloud/lxc/lxc_container.py | 229 ++++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 104 deletions(-) diff --git a/cloud/lxc/lxc_container.py b/cloud/lxc/lxc_container.py index 74c55357501..409695a2e8d 100644 --- a/cloud/lxc/lxc_container.py +++ b/cloud/lxc/lxc_container.py @@ -156,12 +156,12 @@ options: - restarted - absent - frozen - - clone description: - - Define the state of a container. If you use clone the container - will be stopped while the clone operation is happening and upon - completion of the clone the original container state will be - restored. + - Define the state of a container. If you clone a container using + `clone_name` the newly cloned container created in a stopped state. + The running container will be stopped while the clone operation is + happening and upon completion of the clone the original container + state will be restored. required: false default: started container_config: @@ -225,6 +225,7 @@ EXAMPLES = """ - name: Create filesystem container lxc_container: name: test-container-config + backing_store: dir container_log: true template: ubuntu state: started @@ -238,7 +239,7 @@ EXAMPLES = """ # Create an lvm container, run a complex command in it, add additional # configuration to it, create an archive of it, and finally leave the container # in a frozen state. The container archive will be compressed using bzip2 -- name: Create an lvm container +- name: Create a frozen lvm container lxc_container: name: test-container-lvm container_log: true @@ -263,14 +264,6 @@ EXAMPLES = """ - name: Debug info on container "test-container-lvm" debug: var=lvm_container_info -- name: Get information on a given container. - lxc_container: - name: test-container-config - register: config_container_info - -- name: debug info on container "test-container" - debug: var=config_container_info - - name: Run a command in a container and ensure its in a "stopped" state. lxc_container: name: test-container-started @@ -285,19 +278,19 @@ EXAMPLES = """ container_command: | echo 'hello world.' | tee /opt/frozen -- name: Start a container. +- name: Start a container lxc_container: name: test-container-stopped state: started -- name: Run a command in a container and then restart it. +- name: Run a command in a container and then restart it lxc_container: name: test-container-started state: restarted container_command: | echo 'hello world.' | tee /opt/restarted -- name: Run a complex command within a "running" container. +- name: Run a complex command within a "running" container lxc_container: name: test-container-started container_command: | @@ -317,7 +310,10 @@ EXAMPLES = """ archive: true archive_path: /opt/archives -- name: Create an overlayfs container +# Create a container using overlayfs, create an archive of it, create a +# snapshot clone of the container and and finally leave the container +# in a frozen state. The container archive will be compressed using gzip. +- name: Create an overlayfs container archive and clone it lxc_container: name: test-container-overlayfs container_log: true @@ -325,40 +321,42 @@ EXAMPLES = """ state: started backing_store: overlayfs template_options: --release trusty - -- name: Clone a container - lxc_container: - name: test-container-overlayfs - clone_name: test-container-clone - state: clone - -- name: Clone a container using snapshot. - lxc_container: - name: test-container-overlayfs - clone_name: test-container-overlayfs-clone - backing_store: overlayfs clone_snapshot: true - state: clone + clone_name: test-container-overlayfs-clone-snapshot + archive: true + archive_compression: gzip + register: clone_container_info + +- name: debug info on container "test-container" + debug: var=clone_container_info + +- name: Clone a container using snapshot + lxc_container: + name: test-container-overlayfs-clone-snapshot + backing_store: overlayfs + clone_name: test-container-overlayfs-clone-snapshot2 + clone_snapshot: true - name: Create a new container and clone it lxc_container: - name: test-container-new-overlayfs - clone_name: test-container-new-overlayfs-clone - backing_store: overlayfs - clone_snapshot: true - state: clone + name: test-container-new-archive + backing_store: dir + clone_name: test-container-new-archive-clone -- name: Create a new container, clone it, and archive +- name: Archive and clone a container then destroy it lxc_container: - name: test-container-new-overlayfs - clone_name: test-container-new-overlayfs-clone - backing_store: overlayfs - clone_snapshot: true - state: clone + name: test-container-new-archive + state: absent + clone_name: test-container-new-archive-destroyed-clone archive: true archive_compression: gzip -- name: Destroy a container. +- name: Start a cloned container. + lxc_container: + name: test-container-new-archive-destroyed-clone + state: started + +- name: Destroy a container lxc_container: name: "{{ item }}" state: absent @@ -369,8 +367,12 @@ EXAMPLES = """ - test-container-lvm - test-container-config - test-container-overlayfs - - test-container-clone - test-container-overlayfs-clone + - test-container-overlayfs-clone-snapshot + - test-container-overlayfs-clone-snapshot2 + - test-container-new-archive + - test-container-new-archive-clone + - test-container-new-archive-destroyed-clone """ @@ -518,18 +520,16 @@ def create_script(command): f.close() # Ensure the script is executable. - os.chmod(script_file, 0755) + os.chmod(script_file, 1755) # Get temporary directory. tempdir = tempfile.gettempdir() # Output log file. - stdout = path.join(tempdir, 'lxc-attach-script.log') - stdout_file = open(stdout, 'ab') + stdout_file = open(path.join(tempdir, 'lxc-attach-script.log'), 'ab') # Error log file. - stderr = path.join(tempdir, 'lxc-attach-script.err') - stderr_file = open(stderr, 'ab') + stderr_file = open(path.join(tempdir, 'lxc-attach-script.err'), 'ab') # Execute the script command. try: @@ -561,6 +561,7 @@ class LxcContainerManagement(object): self.container_name = self.module.params['name'] self.container = self.get_container_bind() self.archive_info = None + self.clone_info = None def get_container_bind(self): return lxc.Container(name=self.container_name) @@ -735,7 +736,7 @@ class LxcContainerManagement(object): self._container_startup() self.container.freeze() - def _clone(self, count=0): + def _container_create_clone(self): """Clone a new LXC container from an existing container. This method will clone an existing container to a new container using @@ -751,66 +752,51 @@ class LxcContainerManagement(object): state. """ - self.check_count(count=count, method='clone') - if self._container_exists(container_name=self.container_name): - # Ensure that the state of the original container is stopped - container_state = self._get_state() - if container_state != 'stopped': - self.state_change = True - self.container.stop() + # Ensure that the state of the original container is stopped + container_state = self._get_state() + if container_state != 'stopped': + self.state_change = True + self.container.stop() - build_command = [ - self.module.get_bin_path('lxc-clone', True), - ] + build_command = [ + self.module.get_bin_path('lxc-clone', True), + ] - build_command = self._add_variables( - variables_dict=self._get_vars( - variables=LXC_COMMAND_MAP['clone']['variables'] - ), - build_command=build_command - ) + build_command = self._add_variables( + variables_dict=self._get_vars( + variables=LXC_COMMAND_MAP['clone']['variables'] + ), + build_command=build_command + ) - # Load logging for the instance when creating it. - if self.module.params.get('clone_snapshot') in BOOLEANS_TRUE: - build_command.append('--snapshot') + # Load logging for the instance when creating it. + if self.module.params.get('clone_snapshot') in BOOLEANS_TRUE: + build_command.append('--snapshot') + # Check for backing_store == overlayfs if so force the use of snapshot + # If overlay fs is used and snapshot is unset the clone command will + # fail with an unsupported type. + elif self.module.params.get('backing_store') == 'overlayfs': + build_command.append('--snapshot') - rc, return_data, err = self._run_command(build_command) - if rc != 0: - message = "Failed executing lxc-clone." - self.failure( - err=err, rc=rc, msg=message, command=' '.join( - build_command - ) + rc, return_data, err = self._run_command(build_command) + if rc != 0: + message = "Failed executing lxc-clone." + self.failure( + err=err, rc=rc, msg=message, command=' '.join( + build_command ) - else: - self.state_change = True - # Restore the original state of the origin container if it was - # not in a stopped state. - if container_state == 'running': - self.container.start() - elif container_state == 'frozen': - self.container.start() - self.container.freeze() - - # Change the container name context to the new cloned container - # This enforces that the state of the new cloned container will be - # "stopped". - self.state = 'stopped' - self.container_name = self.module.params['clone_name'] - self.container = self.get_container_bind() - - # Return data - self._execute_command() - - # Perform any configuration updates - self._config() - - # Check if the container needs to have an archive created. - self._check_archive() + ) else: - self._create() - count += 1 - self._clone(count) + self.state_change = True + # Restore the original state of the origin container if it was + # not in a stopped state. + if container_state == 'running': + self.container.start() + elif container_state == 'frozen': + self.container.start() + self.container.freeze() + + return True def _create(self): """Create a new LXC container. @@ -965,6 +951,23 @@ class LxcContainerManagement(object): 'archive': self._container_create_tar() } + def _check_clone(self): + """Create a compressed archive of a container. + + This will store archive_info in as self.archive_info + """ + + clone_name = self.module.params.get('clone_name') + if clone_name: + if not self._container_exists(container_name=clone_name): + self.clone_info = { + 'cloned': self._container_create_clone() + } + else: + self.clone_info = { + 'cloned': False + } + def _destroyed(self, timeout=60): """Ensure a container is destroyed. @@ -979,6 +982,9 @@ class LxcContainerManagement(object): # Check if the container needs to have an archive created. self._check_archive() + # Check if the container is to be cloned + self._check_clone() + if self._get_state() != 'stopped': self.state_change = True self.container.stop() @@ -1028,6 +1034,9 @@ class LxcContainerManagement(object): # Check if the container needs to have an archive created. self._check_archive() + + # Check if the container is to be cloned + self._check_clone() else: self._create() count += 1 @@ -1055,6 +1064,9 @@ class LxcContainerManagement(object): # Check if the container needs to have an archive created. self._check_archive() + + # Check if the container is to be cloned + self._check_clone() else: self._create() count += 1 @@ -1082,6 +1094,9 @@ class LxcContainerManagement(object): # Check if the container needs to have an archive created. self._check_archive() + + # Check if the container is to be cloned + self._check_clone() else: self._create() count += 1 @@ -1122,6 +1137,9 @@ class LxcContainerManagement(object): # Check if the container needs to have an archive created. self._check_archive() + + # Check if the container is to be cloned + self._check_clone() else: self._create() count += 1 @@ -1581,6 +1599,9 @@ class LxcContainerManagement(object): if self.archive_info: outcome.update(self.archive_info) + if self.clone_info: + outcome.update(self.clone_info) + self.module.exit_json( changed=self.state_change, lxc_container=outcome