def discover_image_tag(self, image, tag_from_label=None): dockerc = Client(base_url='unix://var/run/docker.sock', version='auto') image_name, colon, tag = image.partition(':') if not tag: tag = 'latest' image = '%s:%s' % (image_name, tag) self._pull_retry(dockerc, image) i = dockerc.inspect_image(image) labels = i['Config']['Labels'] label_keys = ', '.join(labels.keys()) if not tag_from_label: raise ImageUploaderException( 'No label specified. Available labels: %s' % label_keys) tag_label = labels.get(tag_from_label) if tag_label is None: raise ImageUploaderException( 'Image %s has no label %s. Available labels: %s' % (image, tag_from_label, label_keys)) # confirm the tag exists by pulling it, which should be fast # because that image has just been pulled versioned_image = '%s:%s' % (image_name, tag_label) self._pull_retry(dockerc, versioned_image) return tag_label
def _inspect(image, insecure=False): cmd = ['skopeo', 'inspect'] if insecure: cmd.append('--tls-verify=false') cmd.append(image) LOG.info('Running %s' % ' '.join(cmd)) env = os.environ.copy() process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() if process.returncode != 0: not_found_msgs = ( u'manifest unknown', # returned by docker.io u'requested access to the resource is denied') if any(n in err for n in not_found_msgs): raise ImageNotFoundException('Not found image: %s\n%s' % (image, err)) raise ImageUploaderException('Error inspecting image: %s\n%s' % (image, err)) return json.loads(out)
def _push(dockerc, image, tag=None): LOG.debug('Pushing %s' % image) for line in dockerc.push(image, tag=tag, stream=True): status = json.loads(line) if 'error' in status: LOG.warning('docker push failed: %s' % status['error']) raise ImageUploaderException('Could not push image %s' % image)
def _discover_tag_from_inspect(i, image, tag_from_label=None, fallback_tag=None): labels = i.get('Labels', {}) label_keys = ', '.join(labels.keys()) if not tag_from_label: raise ImageUploaderException( 'No label specified. Available labels: %s' % label_keys ) if "{" in tag_from_label: try: tag_label = tag_from_label.format(**labels) except ValueError as e: raise ImageUploaderException(e) except KeyError as e: if fallback_tag: tag_label = fallback_tag else: raise ImageUploaderException( 'Image %s %s. Available labels: %s' % (image, e, label_keys) ) else: tag_label = labels.get(tag_from_label) if tag_label is None: if fallback_tag: tag_label = fallback_tag else: raise ImageUploaderException( 'Image %s has no label %s. Available labels: %s' % (image, tag_from_label, label_keys) ) # confirm the tag exists by checking for an entry in RepoTags repo_tags = i.get('RepoTags', []) if tag_label not in repo_tags: raise ImageUploaderException( 'Image %s has no tag %s.\nAvailable tags: %s' % (image, tag_label, ', '.join(repo_tags)) ) return tag_label
def _pull_retry(self, dockerc, image, tag=None): retval = -1 count = 0 while retval != 0: if count >= 5: raise ImageUploaderException('Could not pull image %s' % image) count += 1 retval = self._pull(dockerc, image, tag) if retval != 0: time.sleep(3) self.logger.warning('retrying pulling image: %s' % image)
def test_images_match(self, mock_inspect): mock_inspect.side_effect = [{'Digest': 'a'}, {'Digest': 'b'}] self.assertFalse(self.uploader._images_match('foo', 'bar', set())) mock_inspect.side_effect = [{'Digest': 'a'}, {'Digest': 'a'}] self.assertTrue(self.uploader._images_match('foo', 'bar', set())) mock_inspect.side_effect = [{}, {'Digest': 'b'}] self.assertFalse(self.uploader._images_match('foo', 'bar', set())) mock_inspect.side_effect = [{'Digest': 'a'}, {}] self.assertFalse(self.uploader._images_match('foo', 'bar', set())) mock_inspect.side_effect = [None, None] self.assertFalse(self.uploader._images_match('foo', 'bar', set())) mock_inspect.side_effect = ImageUploaderException() self.assertFalse(self.uploader._images_match('foo', 'bar', set()))
def _inspect(image, insecure=False): cmd = ['skopeo', 'inspect'] if insecure: cmd.append('--tls-verify=false') cmd.append(image) LOG.info('Running %s' % ' '.join(cmd)) env = os.environ.copy() process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = process.communicate() if process.returncode != 0: raise ImageUploaderException('Error inspecting image: %s\n%s' % (image, err)) return json.loads(out)
def run_modify_playbook(modify_role, modify_vars, source_image, target_image, append_tag): vars = {} if modify_vars: vars.update(modify_vars) vars['source_image'] = source_image vars['target_image'] = target_image vars['modified_append_tag'] = append_tag LOG.info('Playbook variables: \n%s' % yaml.safe_dump(vars, default_flow_style=False)) playbook = [{ 'hosts': 'localhost', 'tasks': [{ 'name': 'Import role %s' % modify_role, 'import_role': { 'name': modify_role }, 'vars': vars }] }] LOG.info('Playbook: \n%s' % yaml.safe_dump(playbook, default_flow_style=False)) work_dir = tempfile.mkdtemp(prefix='tripleo-modify-image-playbook-') try: action = ansible.AnsiblePlaybookAction(playbook=playbook, work_dir=work_dir, verbosity=3) result = action.run(None) log_path = result.get('log_path') if log_path and os.path.isfile(log_path): with open(log_path) as f: LOG.info(f.read()) shutil.rmtree(work_dir) except processutils.ProcessExecutionError as e: LOG.error('%s\nError running playbook in directory: %s' % (e.stdout, work_dir)) raise ImageUploaderException('Modifying image %s failed' % target_image)
def get_uploader(uploader): if uploader == 'docker': return DockerImageUploader() raise ImageUploaderException('Unknown image uploader type')