def update_self(self, count=None, old_container=None, me_list=None, new_image=None): if count == 2: self.logger.debug('God im messy... cleaning myself up.') old_me_id = me_list[0].id if me_list[0].attrs['Created'] < me_list[1].attrs['Created'] else me_list[1].id old_me = self.client.containers.get(old_me_id) old_me_image_id = old_me.image.id old_me.stop() old_me.remove() self.client.images.remove(old_me_image_id) self.logger.debug('Ahhh. All better.') self.monitored = self.monitor_filter() elif count == 1: self.logger.debug('I need to update! Starting the ouroboros ;)') self_name = 'ouroboros-updated' if old_container.name == 'ouroboros' else 'ouroboros' new_config = set_properties(old=old_container, new=new_image, self_name=self_name) try: me_created = self.client.api.create_container(**new_config) new_me = self.client.containers.get(me_created.get("Id")) new_me.start() self.logger.debug('If you strike me down, I shall become ' 'more powerful than you could possibly imagine.') self.logger.debug('https://bit.ly/2VVY7GH') sleep(30) except APIError as e: self.logger.error("Self update failed.") self.logger.error(e)
def recreate(self, container, latest_image): new_config = set_properties(old=container, new=latest_image) self.stop(container) self.remove(container) created = self.client.api.create_container(**new_config) new_container = self.client.containers.get(created.get("Id")) # connect the new container to all networks of the old container for network_name, network_config in container.attrs['NetworkSettings'][ 'Networks'].items(): network = self.client.networks.get(network_config['NetworkID']) try: network.disconnect(new_container.id, force=True) except APIError: pass new_network_config = { 'container': new_container, 'aliases': network_config['Aliases'], 'links': network_config['Links'] } if network_config['IPAMConfig']: new_network_config.update({ 'ipv4_address': network_config['IPAddress'], 'ipv6_address': network_config['GlobalIPv6Address'] }) try: network.connect(**new_network_config) except APIError as e: if any(err in str(e) for err in ['user configured subnets', 'user defined networks']): if new_network_config.get('ipv4_address'): del new_network_config['ipv4_address'] if new_network_config.get('ipv6_address'): del new_network_config['ipv6_address'] network.connect(**new_network_config) else: self.logger.error( 'Unable to attach updated container to network "%s". Error: %s', network.name, e) new_container.start() return new_container
def update_containers(self): updated_count = 0 updated_container_tuples = [] self.monitored = self.monitor_filter() if not self.monitored: self.logger.info('No containers are running or monitored on %s', self.socket) me_list = [c for c in self.client.api.containers() if 'ouroboros' in c['Names'][0].strip('/')] if len(me_list) > 1: self.update_self(count=2, me_list=me_list) for container in self.monitored: current_image = container.image shared_image = [uct for uct in updated_container_tuples if uct[1].id == current_image.id] if shared_image: latest_image = shared_image[0][2] else: try: latest_image = self.pull(current_image) except ConnectionError: continue # If current running container is running latest image if current_image.id != latest_image.id: if container.name in ['ouroboros', 'ouroboros-updated']: self.update_self(old_container=container, new_image=latest_image, count=1) updated_container_tuples.append( (container, current_image, latest_image) ) self.logger.info('%s will be updated', container.name) # new container dict to create new container from new_config = set_properties(old=container, new=latest_image) self.logger.debug('Stopping container: %s', container.name) container.stop() self.logger.debug('Removing container: %s', container.name) try: container.remove() except NotFound as e: self.logger.error("Could not remove container. Error: %s", e) created = self.client.api.create_container(**new_config) new_container = self.client.containers.get(created.get("Id")) new_container.start() if self.config.cleanup: try: self.client.images.remove(current_image.id) except APIError as e: self.logger.error("Could not delete old image for %s, Error: %s", container.name, e) updated_count += 1 self.logger.debug("Incrementing total container updated count") self.data_manager.total_updated[self.socket] += 1 self.data_manager.add(label=container.name, socket=self.socket) self.data_manager.add(label='all', socket=self.socket) if updated_count > 0: self.notification_manager.send(container_tuples=updated_container_tuples, socket=self.socket, notification_type='data') self.notification_manager.send(notification_type='keep_alive')
def update_containers(self): updated_count = 0 updated_container_tuples = [] depends_on_list = [] self.monitored = self.monitor_filter() if not self.monitored: self.logger.info('No containers are running or monitored on %s', self.socket) me_list = [c for c in self.client.api.containers() if 'ouroboros' in c['Names'][0].strip('/')] if len(me_list) > 1: self.update_self(count=2, me_list=me_list) for container in self.monitored: current_image = container.image shared_image = [uct for uct in updated_container_tuples if uct[1].id == current_image.id] if shared_image: latest_image = shared_image[0][2] else: try: latest_image = self.pull(current_image) except ConnectionError: continue if self.config.dry_run: # Ugly hack for repo digest repo_digest_id = current_image.attrs['RepoDigests'][0].split('@')[1] if repo_digest_id != latest_image.id: self.logger.info('dry run : %s would be updated', container.name) continue # If current running container is running latest image if current_image.id != latest_image.id: updated_container_tuples.append( (container, current_image, latest_image) ) if container.name in ['ouroboros', 'ouroboros-updated']: self.data_manager.total_updated[self.socket] += 1 self.data_manager.add(label=container.name, socket=self.socket) self.data_manager.add(label='all', socket=self.socket) self.notification_manager.send(container_tuples=updated_container_tuples, socket=self.socket, kind='update') self.update_self(old_container=container, new_image=latest_image, count=1) self.logger.info('%s will be updated', container.name) # Get container list to restart after update complete depends_on = container.labels.get('com.ouroboros.depends-on', False) if depends_on: depends_on_list.extend([name.strip() for name in depends_on.split(',')]) # new container dict to create new container from new_config = set_properties(old=container, new=latest_image) self.logger.debug('Stopping container: %s', container.name) stop_signal = container.labels.get('com.ouroboros.stop-signal', False) if stop_signal: try: container.kill(signal=stop_signal) except APIError as e: self.logger.error('Cannot kill container using signal %s. stopping normally. Error: %s', stop_signal, e) container.stop() else: container.stop() self.logger.debug('Removing container: %s', container.name) try: container.remove() except NotFound as e: self.logger.error("Could not remove container. Error: %s", e) created = self.client.api.create_container(**new_config) new_container = self.client.containers.get(created.get("Id")) new_container.start() if self.config.cleanup: try: self.client.images.remove(current_image.id) except APIError as e: self.logger.error("Could not delete old image for %s, Error: %s", container.name, e) updated_count += 1 self.logger.debug("Incrementing total container updated count") self.data_manager.total_updated[self.socket] += 1 self.data_manager.add(label=container.name, socket=self.socket) self.data_manager.add(label='all', socket=self.socket) if depends_on_list: depends_on_containers = [] for name in list(set(depends_on_list)): try: depends_on_containers.append(self.client.containers.get(name)) except NotFound: self.logger.error("Could not find dependant container %s on socket %s. Ignoring", name, self.socket) if depends_on_containers: for container in depends_on_containers: self.logger.debug('Restarting dependant container %s', container.name) container.restart() if updated_count > 0: self.notification_manager.send(container_tuples=updated_container_tuples, socket=self.socket, kind='update')