def _run_rsync(self): """ run rsync to pull out the rootfs /etc/ dir (later it is re-mounted inside the container so RHI can edit any needed files """ # rsync -aqPS ${IMAGE}/etc . if os.path.exists(self.tmp_image_dir + "etc/"): cmd = ['rsync', '-aqPS', self.tmp_image_dir + "etc/", "/home/temp_etc/"] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Rysnc unable to copy files: %s ' % cmd) # FIXME for some reason, some versions of RHEL containers don't have these dirs? # odd right? if not os.path.exists("/home/temp_etc/pki"): cmd = ['mkdir', '/home/temp_etc/etc/pki'] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to make temporary directory: %s ' % cmd) if not os.path.exists("/home/temp_etc/pki/consumer"): cmd = ['mkdir', '/home/temp_etc/pki/consumer'] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to make temporary directory: %s ' % cmd)
def _remove_var_tmp_dir(self): """ remove the old location of where RHAI's output was stored """ cmd = ['rm', '-rf', self.vartmp_dir] r = util.subp(cmd) if r.return_code != 0: print "vartmp dir did not remove"
def _copy_launcher(self): """ copy the launching script into the rootfs/mnt dir """ cmd = ['cp', '/home/insights-docker/launcher.sh', self.tmp_image_dir + '/mnt/'] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to copy file: %s ' % cmd)
def _copy_launcher(self): """ copy the launching script into the rootfs/mnt dir """ cmd = ['cp', './launcher.sh', self.tmp_image_dir + '/mnt/'] r = util.subp(cmd) if r.return_code != 0: print "could not copy launcher!"
def _copy_resolve_conf(self): """ copy the host machines resolve.conf and put it into the rootfs' /etc/ dir """ cmd = ['cp', '/etc/resolv.conf', self.tmp_image_dir + '/etc/'] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to copy file: %s ' % cmd)
def _mount_overlay(self, identifier): """ OverlayFS mount backend. """ cid = self._identifier_as_cid(identifier) cinfo = self.client.inspect_container(cid) ld, ud, wd = '', '', '' try: ld = cinfo['GraphDriver']['Data']['lowerDir'] ud = cinfo['GraphDriver']['Data']['upperDir'] wd = cinfo['GraphDriver']['Data']['workDir'] except: ld, ud, wd = DockerMount._no_gd_api_overlay(cid) options = ['ro', 'lowerdir=' + ld, 'upperdir=' + ud, 'workdir=' + wd] optstring = ','.join(options) cmd = ['mount', '-t', 'overlay', '-o', optstring, 'overlay', self.mountpoint] status = util.subp(cmd) if status.return_code != 0: self._cleanup_container(cinfo) raise MountError('Failed to mount OverlayFS device.\n%s' % status.stderr.decode(sys.getdefaultencoding())) return cid
def inspect(self, obj_id): # returns dict representation of "docker inspect ID" cmd = ['docker', 'inspect', obj_id] r = util.subp(cmd) if r.return_code != 0: raise Exception('Unable to inspect object: %s' % obj_id) return json.loads(r.stdout)
def getDmsetupLs(): cmd = ['dmsetup', 'ls'] r = util.subp(cmd) if r.return_code != 0: print r.stderr return -1 return r.stdout
def _get_fs(thin_pathname): """ Returns the file system type (xfs, ext4) of a given device """ cmd = ['lsblk', '-o', 'FSTYPE', '-n', thin_pathname] fs_return = util.subp(cmd) return fs_return.stdout.strip()
def unmount_path(path): """ Unmounts the directory specified by path. """ r = util.subp(['umount', path]) if r.return_code != 0: raise ValueError(r.stderr)
def remove_image(self, image_id): """ force removes image image_id """ cmd = ['docker', 'rmi', '-f', image_id] out = util.subp(cmd) if out.return_code != 0: print "image was not deleted"
def _remove_thin_device(name): """ Destroys a thin device via subprocess call. """ r = util.subp(['dmsetup', 'remove', name]) if r.return_code != 0: raise MountError('Could not remove thin device:\n' + r.stderr)
def chroot_and_run(self): """ give the chroot cmda and run the launcher script in the rootfs """ cmd = ['chroot', self.tmp_image_dir, '/mnt/launcher.sh'] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to start Insights Script: %s ' % cmd)
def remove_old_data(): """ deleted old output """ import util cmd = ['rm', '-rf', "/var/tmp/docker/"] r = util.subp(cmd) if r.return_code != 0: print "old data was not deleted"
def unmount_path(path, force=False): """ Unmounts the directory specified by path. """ r = util.subp(['umount', path]) if not force: if r.return_code != 0: raise ValueError(r.stderr)
def chroot_and_run(self): """ give the chroot cmda and run the launcher script in the rootfs """ cmd = ['chroot', self.tmp_image_dir, '/mnt/launcher.sh'] r = util.subp(cmd) if r.return_code != 0: print "could not chroot and run!" sys.exit()
def commit(self, container): """ commits the container into a new image with the given tag """ cmd = ['docker', 'commit', '-c', "ENV _RHAI_TEMP_CONTAINER=True", container] out = util.subp(cmd) if out.return_code != 0: print "image was not commited" return out.stdout.strip()
def inspect(self, obj_id): """ returns a dict of the inspection of a container or image """ cmd = ['docker', 'inspect', obj_id] out = util.subp(cmd) trim_out = out.stdout.strip() ret = json.loads(trim_out[2:-2]) return ret
def remove_old_data(): """ deleted old output """ temp_dir = "/var/tmp/docker/" cmd = ['rm', '-rf', temp_dir] r = util.subp(cmd) if r.return_code != 0: raise ValueError(str("Unable to remove directory %s."% temp_dir))
def create_dirs(self): """ creates a dir of every entry in self.dir_list """ for d in self.dir_list: if not os.path.exists(d): cmd = ['mkdir', d] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Not able to mount directory %s' % d )
def create_dirs(self): """ creates a dir of every entry in self.dir_list """ for d in self.dir_list: if not os.path.exists(d): cmd = ['mkdir', d] r = util.subp(cmd) if r.return_code != 0: print "temp dirs did not mount"
def _first_mounts(self): """ Mount the intial directories into the rootfs """ dir_list = ["/sys", "/proc", "/dev", "/tmp"] for d in dir_list: cmd = ['mount', '-o', "bind", d, self.tmp_image_dir + d] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to mount directory %s to %s' % (d, self.tmp_image_dir + d) ) # FIXME, can't remount shit into here cause # VirtualBox's shared folders are read only, maybe not needed in prod version cmd = ['mount', '-o', "bind", "/home/temp_etc/", self.tmp_image_dir + "etc"] r = util.subp(cmd) if r.return_code != 0: raise EmulatorError('Unable to mount directory /home/temp_etc/ ' + ' to %s ' % self.tmp_image_dir + 'etc')
def get_dev_at_mountpoint(mntpoint): """ Retrieves the device mounted at mntpoint, or raises MountError if none. """ results = util.subp(['findmnt', '-o', 'SOURCE', mntpoint]) if results.return_code != 0: raise MountError('No device mounted at ' + mntpoint) return results.stdout.replace('SOURCE\n', '').strip().split('\n')[-1]
def _first_mounts(self): """ Mount the intial directories into the rootfs """ dir_list = ["/sys", "/proc", "/dev", "/tmp", "etc"] for d in dir_list: cmd = ['mount', '-o', "bind", d, self.tmp_image_dir + d] r = util.subp(cmd) if r.return_code != 0: print "mounting broke" print d
def remove_thin_device(name,force=False): """ Destroys a thin device via subprocess call. """ cmd = ['dmsetup', 'remove', '--retry', name] r = util.subp(cmd) if not force: if r.return_code != 0: raise MountError('Could not remove thin device:\n%s' % r.stderr.decode(sys.getdefaultencoding()).split("\n")[0])
def remove_dirs(self): """ remove directories in dir_list with a few exception dirs """ for d in self.dir_list: if d not in [self.insights_output_dir, self.insights_dir, self.vartmp_dir]: cmd = ['rm', '-rf', d] r = util.subp(cmd) if r.return_code != 0: print "temp dirs did not remove"
def remove_container(self, cont_id): """ *force* removes the given container id, fails if container ID isn't found """ cmd = ['docker', 'rm', '-f', cont_id] out = util.subp(cmd) if out.return_code != 0: #FIXME RAISE EXCEPT HERE print "container ID not found, unable to remove object:" print cont_id
def commit(self, container): """ commits the container into a new image with the given tag """ cmd = [ 'docker', 'commit', '-c', "ENV _RHAI_TEMP_CONTAINER=True", container ] out = util.subp(cmd) if out.return_code != 0: print "image was not commited" return out.stdout.strip()
def _is_device_active(device): """ Checks dmsetup to see if a device is already active """ cmd = ['dmsetup', 'info', device] dmsetup_info = util.subp(cmd) for dm_line in dmsetup_info.stdout.split("\n"): line = dm_line.split(':') if ('State' in line[0].strip()) and ('ACTIVE' in line[1].strip()): return True return False
def create_container(self, iid): """ creates a container from image iid and returns the new container's id """ cmd = ['docker', 'create', '--env=_RHAI_TEMP_CONTAINER', iid, '/bin/true'] out = util.subp(cmd) if out.return_code != 0: print "container was not created" return out.stdout.strip()
def remove_thin_device(name, force=False): """ Destroys a thin device via subprocess call. """ cmd = ['dmsetup', 'remove', '--retry', name] r = util.subp(cmd) if not force: if r.return_code != 0: raise MountError( 'Could not remove thin device:\n%s' % r.stderr.decode(sys.getdefaultencoding()).split("\n")[0])
def _activate_thin_device(name, dm_id, size, pool): """ Provisions an LVM device-mapper thin device reflecting, DM device id 'dm_id' in the docker pool. """ table = '0 %d thin /dev/mapper/%s %s' % (int(size) // 512, pool, dm_id) cmd = ['dmsetup', 'create', name, '--table', table] r = util.subp(cmd) if r.return_code != 0: raise MountError('Failed to create thin device: %s' % r.stderr.decode(sys.getdefaultencoding()))
def _activate_thin_device(name, dm_id, size, pool): """ Provisions an LVM device-mapper thin device reflecting, DM device id 'dm_id' in the docker pool. """ table = '0 {0} thin /dev/mapper/{1} {2}'.format( int(size) / 512, pool, dm_id) cmd = ['dmsetup', 'create', name, '--table', table] r = util.subp(cmd) if r.return_code != 0: raise MountError('Failed to create thin device: ' + r.stderr)
def _activate_thin_device(name, dm_id, size, pool): """ Provisions an LVM device-mapper thin device reflecting, DM device id 'dm_id' in the docker pool. """ table = '0 {0} thin /dev/mapper/{1} {2}'.format(int(size)/512, pool, dm_id) cmd = ['dmsetup', 'create', name, '--table', table] r = util.subp(cmd) if r.return_code != 0: raise MountError('Failed to create thin device: ' + r.stderr)
def _activate_thin_device(name, dm_id, size, pool): """ Provisions an LVM device-mapper thin device reflecting, DM device id 'dm_id' in the docker pool. """ table = '0 %d thin /dev/mapper/%s %s' % (int(size)//512, pool, dm_id) cmd = ['dmsetup', 'create', name, '--table', table] r = util.subp(cmd) if r.return_code != 0: raise MountError('Failed to create thin device: %s' % r.stderr.decode(sys.getdefaultencoding()))
def remove_dirs(self): """ remove directories in dir_list with a few exception dirs """ for d in self.dir_list: if d not in [ self.insights_output_dir, self.insights_dir, self.vartmp_dir ]: cmd = ['rm', '-rf', d] r = util.subp(cmd) if r.return_code != 0: print "temp dirs did not remove"
def images(self): """ returns a list of all image ids """ cmd = ['docker', 'images', '-q', '--no-trunc'] out = util.subp(cmd) trim_out = out.stdout.strip() return_list = [] for line in trim_out.split('\n'): return_list.append(line) # return a set to remove dup ID's return list(set(return_list))
def info(self): """ returns a dict of all of the docker info data""" cmd = ['docker', 'info'] out = util.subp(cmd) trim_out = out.stdout.strip() return_dict = {} for line in trim_out.split('\n'): tmp_list = line.split(':', 1) return_dict[tmp_list[0].strip()] = tmp_list[1].strip() return return_dict
def create_container(self, iid): """ creates a container from image iid and returns the new container's id """ cmd = [ 'docker', 'create', '--env=_RHAI_TEMP_CONTAINER', iid, '/bin/true' ] out = util.subp(cmd) if out.return_code != 0: print "container was not created" return out.stdout.strip()
def driver(self): # returns the storage driver docker is using cmd = ['docker', 'info'] r = util.subp(cmd) if r.return_code != 0: raise Exception('Unable to get docker info') for line in r.stdout.strip().split('\n'): if line.startswith('Storage Driver'): pre, _, post = line.partition(':') return post.strip() raise Exception('Unable to get docker storage driver')
def dm_pool(self): # ONLY FOR DEVICEMAPPER # returns the docker-pool docker is using cmd = ['docker', 'info'] r = util.subp(cmd) if r.return_code != 0: raise Exception('Unable to get docker info') for line in r.stdout.strip().split('\n'): if line.strip().startswith('Pool Name'): pre, _, post = line.partition(':') return post.strip() raise Exception('Unable to get docker pool name')
def gather_data(self, ims): """ Move the output dir into a designed output dir in /var/tmp/ """ obj_type = ('images' if ims is True else 'containers') output_path = self.insights_output_dir + obj_type if not os.path.exists(output_path): cmd = ['mkdir', output_path] r = util.subp(cmd) if r.return_code != 0: print "could not make output directory" files = os.listdir(self.vartmp_dir) for f in files: cmd = ['mv', self.vartmp_dir + f, output_path] r = util.subp(cmd) if r.return_code != 0: print "could not move dir into output dir" print f print cmd self._remove_var_tmp_dir()
def containers(self, running=True): """ returns a list of all container ids """ if running: cmd = ['docker', 'ps', '-q', '--no-trunc'] else: cmd = ['docker', 'ps', '-a', '-q', '--no-trunc'] out = util.subp(cmd) trim_out = out.stdout.strip() return_list = [] for line in trim_out.split('\n'): return_list.append(line) return return_list
def unmount(self): """ unmount all mounted directories """ dir_list = [ "/var/tmp", "/var/log", "/mnt/opt/python", "/mnt", "/etc/pki/consumer", "/root/", "/sys", "/proc", "/dev", "/tmp", "etc" ] for d in dir_list: cmd = ['umount', self.tmp_image_dir + d] r = util.subp(cmd) if r.return_code != 0: print "unmounting broke" print d
def mount_path(source, target, bind=False): """ Subprocess call to mount dev at path. """ cmd = ['mount'] if bind: cmd.append('--bind') cmd.append(source) cmd.append(target) r = util.subp(cmd) if r.return_code != 0: raise MountError('Could not mount docker container:\n' + ' '.join(cmd) + '\n%s' % r.stderr.decode(sys.getdefaultencoding()))
def _run_rsync(self): """ run rsync to pull out the rootfs /etc/ dir (later it is re-mounted inside the container so RHAI can edit any needed files """ # rsync -aqPS ${IMAGE}/etc . if os.path.exists(self.tmp_image_dir + "etc/"): cmd = ['rsync', '-aqPS', self.tmp_image_dir + "etc/", "./etc/"] r = util.subp(cmd) if r.return_code != 0: print "rsync didn't copy correctly" # FIXME for some reason, some versions of RHEL containers don't have these dirs? # odd right? if not os.path.exists("./etc/pki"): cmd = ['mkdir', './etc/pki'] r = util.subp(cmd) if r.return_code != 0: print "could not make temp pki directory" if not os.path.exists("./etc/pki/consumer"): cmd = ['mkdir', './etc/pki/consumer'] r = util.subp(cmd) if r.return_code != 0: print "could not make temp consumer directory"
def _prep_etc_dir(self): """ remove the RHAI dir from the mounted etc dir in the rootfs and Copy the RHAI source code into the rootfs etc dir """ cmds = [] cmds.append( ['rm', '-rf', self.tmp_image_dir + '/etc/redhat-access-insights']) cmds.append([ 'cp', '-r', self.insights_dir + '/etc/', self.tmp_image_dir + '/etc/redhat-access-insights' ]) for c in cmds: r = util.subp(c) if r.return_code != 0: print "could not final prep the image's etc directory"
def mount_path(source, target, optstring='', bind=False): """ Subprocess call to mount dev at path. """ cmd = ['mount'] if bind: cmd.append('--bind') if optstring: cmd.append('-o') cmd.append(optstring) cmd.append(source) cmd.append(target) r = util.subp(cmd) if r.return_code != 0: raise MountError('Could not mount docker container:\n' + ' '.join(cmd) + '\n' + r.stderr)
def _get_overlay_mount_cid(self): """ Returns the cid of the container mounted at mountpoint. """ cmd = ['findmnt', '-o', 'OPTIONS', '-n', self.mountpoint] r = util.subp(cmd) if r.return_code != 0: raise MountError('No devices mounted at that location.') optstring = r.stdout.strip().split('\n')[-1] upperdir = [ o.replace('upperdir=', '') for o in optstring.split(',') if o.startswith('upperdir=') ][0] cdir = upperdir.rsplit('/', 1)[0] if not cdir.startswith('/var/lib/docker/overlay/'): raise MountError('The device mounted at that location is not a ' 'docker container.') return cdir.replace('/var/lib/docker/overlay/', '')
def containers(self, allc=False, quiet=False): # returns a list of dicts, each dict is an containers's information # except when quiet is used - which returns a list of container ids # dict keys: # Status # Created # Image # Labels # NetworkSettings # HostConfig # ImageID # Command # Names # Id # Ports cmd = ['docker', 'ps', '-q'] if allc: cmd.append("-a") r = util.subp(cmd) if r.return_code != 0: raise Exception('Unable to get docker containers') containers = r.stdout.strip().split('\n') if quiet: return containers else: conts = [] for i in containers: inspec = self.inspect(i) inspec = inspec[0] dic = {} dic['Status'] = inspec['State']['Status'] dic['Created'] = inspec['Created'] dic['Image'] = inspec['Config']['Image'] dic['Labels'] = inspec['Config']['Labels'] dic['NetworkSettings'] = inspec['NetworkSettings'] dic['HostConfig'] = inspec['HostConfig'] dic['ImageID'] = inspec['Image'] dic['Command'] = inspec['Config']['Cmd'] dic['Names'] = inspec['Name'] dic['Id'] = inspec['Id'] dic['Ports'] = inspec['NetworkSettings']['Ports'] conts.append(dic) return conts
def images(self, allI=False, quiet=False): # returns a list of dicts, each dict is an image's information # except when quiet is used - which returns a list of image ids # dict keys: # Created # Labels # VirtualSize # ParentId # RepoTags # RepoDigests # Id # Size cmd = ['docker', 'images', '-q', '--no-trunc'] if allI: cmd.append("-a") r = util.subp(cmd) if r.return_code != 0: raise Exception('Unable to get docker images') images = r.stdout.strip().split('\n') if quiet: return images else: ims = [] for i in images: inspec = self.inspect(i) inspec = inspec[0] dic = {} dic['Created'] = inspec['Created'] if inspec['Config']: dic['Labels'] = inspec['Config']['Labels'] else: dic['Labels'] = {} dic['VirtualSize'] = inspec['VirtualSize'] dic['ParentId'] = inspec['Parent'] dic['RepoTags'] = inspec['RepoTags'] dic['RepoDigests'] = inspec['RepoDigests'] dic['Id'] = inspec['Id'] dic['Size'] = inspec['Size'] ims.append(dic) return ims
def _mount_overlay(self, identifier, options): """ OverlayFS mount backend. """ if os.geteuid() != 0: raise MountError('Insufficient privileges to mount device.') if self.live: raise MountError('The OverlayFS backend does not support live ' 'mounts.') elif 'rw' in options: raise MountError('The OverlayFS backend does not support ' 'writeable mounts.') cid = self._identifier_as_cid(identifier) # cinfo = self.client.inspect_container(cid) cinfo = self.docker_client.inspect(cid) ld, ud, wd = '', '', '' try: #FIXME, GraphDriver isn't in inspect container output ld = cinfo['GraphDriver']['Data']['lowerDir'] ud = cinfo['GraphDriver']['Data']['upperDir'] wd = cinfo['GraphDriver']['Data']['workDir'] except: ld, ud, wd = DockerMount._no_gd_api_overlay(cid) options += ['ro', 'lowerdir=' + ld, 'upperdir=' + ud, 'workdir=' + wd] optstring = ','.join(options) cmd = [ 'mount', '-t', 'overlay', '-o', optstring, 'overlay', self.mountpoint ] status = util.subp(cmd) if status.return_code != 0: self._cleanup_container(cinfo) raise MountError('Failed to mount OverlayFS device.\n' + status.stderr.decode(sys.getdefaultencoding()))
def _copy_resolve_conf(self): """ copy the host machines resolve.conf and put it into the rootfs' /etc/ dir """ cmd = ['cp', '/etc/resolv.conf', self.tmp_image_dir + '/etc/'] r = util.subp(cmd) if r.return_code != 0: print "could not make copy host's resolve.conf"