Exemple #1
0
    def get_config(self, spec="Entrypoint", delim=None, old_version=False):
        '''get_config returns a particular spec (default is Entrypoint) 
        from a VERSION 1 manifest obtained with get_manifest.
        :param manifest: the manifest obtained from get_manifest
        :param spec: the key of the spec to return, default is "Entrypoint"
        :param delim: Given a list, the delim to use to join the entries. Default is newline
        '''
        manifest = self.get_manifest(old_version=old_version)

        cmd = None

        # Version 1 of the manifest has more detailed metadata
        if old_version:
            if "history" in manifest:
                for entry in manifest['history']:
                    if 'v1Compatibility' in entry:
                        entry = json.loads(entry['v1Compatibility'])
                        if "config" in entry:
                            if spec in entry["config"]:
                                cmd = entry["config"][spec]

            # Standard is to include commands like ['/bin/sh']
            if isinstance(cmd, list):
                if delim is None:
                    delim = "\n"
                cmd = delim.join(cmd)
            bot.verbose("Found Docker config (%s) %s" % (spec, cmd))

        else:
            if "config" in manifest:
                if spec in manifest['config']:
                    cmd = manifest['config'][spec]
        return cmd
Exemple #2
0
def extract_metadata(manifest, labelfile=None, prefix=None):
    '''extract_metadata will write a file of metadata from shub
    :param manifest: the manifest to use
    '''

    if prefix is None:
        prefix = ""
    prefix = prefix.upper()

    source = 'Hub'
    if 'frozen' in manifest:
        source = 'Registry'

    metadata = manifest.copy()
    remove_fields = ['files', 'spec', 'metrics']
    for remove_field in remove_fields:
        if remove_field in metadata:
            del metadata[remove_field]

    if labelfile is not None:
        for key, value in metadata.items():
            key = "%s%s" % (prefix, key)
            value = ADD(key=key,
                        value=value,
                        jsonfile=labelfile,
                        force=True)

        bot.verbose("Saving Singularity %s metadata to %s" % (source,
                                                              labelfile))
    return metadata
Exemple #3
0
    def get_tags(self, return_response=False):
        '''get_tags will return the tags for a repo using the
        Docker Version 2.0 Registry API
        '''
        registry = self.registry
        if registry is None:
            registry = self.api_base

        registry = add_http(registry)  # make sure we have a complete url

        base = "%s/%s/%s/tags/list" % (registry, self.api_version,
                                       self.repo_name)

        bot.verbose("Obtaining tags: %s" % base)

        # We use get_tags for a testing endpoint in update_token
        response = self.get(base, return_response=return_response)

        if return_response:
            return response

        try:
            response = json.loads(response)
            return response['tags']
        except Exception:
            bot.error("Error obtaining tags: %s" % base)
            sys.exit(1)
Exemple #4
0
    def get_tags(self,return_response=False):
        '''get_tags will return the tags for a repo using the Docker Version 2.0 Registry API
        :param namespace: the namespace (eg, "library")
        :param repo_name: the name for the repo (eg, "ubuntu")
        :param registry: the docker registry to use (default will use index.docker.io)
        :param auth: authorization header (default None)
        '''
        registry = self.registry
        if registry == None:
            registry = self.api_base
        
        registry = add_http(registry) # make sure we have a complete url

        base = "%s/%s/%s/%s/tags/list" %(registry,self.api_version,self.namespace,self.repo_name)
        bot.verbose("Obtaining tags: %s" %base)

        # We use get_tags for a testing endpoint in update_token
        response = self.get(base,
                            return_response=return_response)

        if return_response:
            return response

        try:
            response = json.loads(response)
            return response['tags']
        except:
            bot.error("Error obtaining tags: %s" %base)
            sys.exit(1)
Exemple #5
0
    def get_manifest(self,old_version=False):
        '''get_manifest should return an image manifest for a particular repo and tag. 
        The image details are extracted when the client is generated.
        :param old_version: return version 1 (for cmd/entrypoint), default False
        '''
        registry = self.registry
        if registry == None:
            registry = self.api_base
        registry = add_http(registry) # make sure we have a complete url

        base = "%s/%s/%s/%s/manifests" %(registry,self.api_version,self.namespace,self.repo_name)
        if self.version is not None:
            base = "%s/%s" %(base,self.version)
        else:
            base = "%s/%s" %(base,self.repo_tag)
        bot.verbose("Obtaining manifest: %s" %base)
    
        headers = self.headers
        if old_version == True:
            headers['Accept'] = 'application/json' 

        response = self.get(base,headers=self.headers)

        try:
            response = json.loads(response)

        except:
            # If the call fails, give the user a list of acceptable tags
            tags = self.get_tags()
            print("\n".join(tags))
            repo_uri = "%s/%s:%s" %(self.namespace,self.repo_name,self.repo_tag)
            bot.error("Error getting manifest for %s, exiting." %repo_uri)
            sys.exit(1)

        return response
Exemple #6
0
def extract_metadata(manifest, labelfile=None, prefix=None):
    '''extract_metadata will write a file of metadata from shub
    :param manifest: the manifest to use
    '''

    if prefix is None:
        prefix = ""
    prefix = prefix.upper()

    source = 'Hub'
    if 'frozen' in manifest:
        source = 'Registry'

    metadata = manifest.copy()
    remove_fields = ['files', 'spec', 'metrics']
    for remove_field in remove_fields:
        if remove_field in metadata:
            del metadata[remove_field]

    if labelfile is not None:
        for key, value in metadata.items():
            key = "%s%s" % (prefix, key)
            value = ADD(key=key, value=value, jsonfile=labelfile, force=True)

        bot.verbose("Saving Singularity %s metadata to %s" %
                    (source, labelfile))
    return metadata
Exemple #7
0
    def get_tags(self, return_response=False):
        '''get_tags will return the tags for a repo using the
        Docker Version 2.0 Registry API
        '''
        registry = self.registry
        if registry is None:
            registry = self.api_base

        registry = add_http(registry)  # make sure we have a complete url

        base = "%s/%s/%s/tags/list" % (registry,
                                       self.api_version,
                                       self.repo_name)

        bot.verbose("Obtaining tags: %s" % base)

        # We use get_tags for a testing endpoint in update_token
        response = self.get(base,
                            return_response=return_response)

        if return_response:
            return response

        try:
            response = json.loads(response)
            return response['tags']
        except Exception:
            bot.error("Error obtaining tags: %s" % base)
            sys.exit(1)
Exemple #8
0
    def get_tags(self, return_response=False):
        '''get_tags will return the tags for a repo using the Docker Version 2.0 Registry API
        :param namespace: the namespace (eg, "library")
        :param repo_name: the name for the repo (eg, "ubuntu")
        :param registry: the docker registry to use (default will use index.docker.io)
        :param auth: authorization header (default None)
        '''
        registry = self.registry
        if registry == None:
            registry = self.api_base

        registry = add_http(registry)  # make sure we have a complete url

        base = "%s/%s/%s/%s/tags/list" % (registry, self.api_version,
                                          self.namespace, self.repo_name)
        bot.verbose("Obtaining tags: %s" % base)

        # We use get_tags for a testing endpoint in update_token
        response = self.get(base, return_response=return_response)

        if return_response:
            return response

        try:
            response = json.loads(response)
            return response['tags']
        except:
            bot.error("Error obtaining tags: %s" % base)
            sys.exit(1)
Exemple #9
0
    def get_config(self,spec="Entrypoint",delim=None,old_version=False):
        '''get_config returns a particular spec (default is Entrypoint) 
        from a VERSION 1 manifest obtained with get_manifest.
        :param manifest: the manifest obtained from get_manifest
        :param spec: the key of the spec to return, default is "Entrypoint"
        :param delim: Given a list, the delim to use to join the entries. Default is newline
        '''
        manifest = self.get_manifest(old_version=old_version)

        cmd = None

        # Version 1 of the manifest has more detailed metadata
        if old_version:
            if "history" in manifest:
                for entry in manifest['history']:
                    if 'v1Compatibility' in entry:
                        entry = json.loads(entry['v1Compatibility'])
                        if "config" in entry:
                            if spec in entry["config"]:
                                cmd = entry["config"][spec]

            # Standard is to include commands like ['/bin/sh']
            if isinstance(cmd,list):
                if delim is None:
                    delim = "\n"
                cmd = delim.join(cmd)
            bot.verbose("Found Docker config (%s) %s" %(spec,cmd))

        else:
            if "config" in manifest:
                if spec in manifest['config']:
                    cmd = manifest['config'][spec]
        return cmd
Exemple #10
0
    def get_layer(self,
                  image_id,
                  download_folder=None,
                  change_perms=False,
                  return_tmp=False):
        '''get_layer will download an image layer (.tar.gz)
        to a specified download folder.
        :param download_folder: if specified, download to folder.
                                Otherwise return response with raw data
        :param change_perms: change permissions additionally
                             (default False to support multiprocessing)
        :param return_tmp: If true, return the temporary file name (and
                             don't rename to the file's final name). Default
                             is False, should be True for multiprocessing
                             that requires extra permission changes
        '''
        registry = self.registry
        if registry is None:
            registry = self.api_base

        # make sure we have a complete url
        registry = add_http(registry)

        # The <name> variable is the namespace/repo_name
        base = "%s/%s/%s/%s/blobs/%s" % (registry, self.api_version,
                                         self.namespace, self.repo_name,
                                         image_id)
        bot.verbose("Downloading layers from %s" % base)

        if download_folder is None:
            download_folder = tempfile.mkdtemp()

        download_folder = "%s/%s.tar.gz" % (download_folder, image_id)

        # Update user what we are doing
        bot.debug("Downloading layer %s" % image_id)

        # Step 1: Download the layer atomically
        file_name = "%s.%s" % (download_folder,
                               next(tempfile._get_candidate_names()))
        tar_download = self.download_atomically(url=base, file_name=file_name)
        bot.debug('Download of raw file (pre permissions fix) is %s' %
                  tar_download)

        # Step 2: Fix Permissions?
        if change_perms:
            tar_download = change_tar_permissions(tar_download)

        if return_tmp is True:
            return tar_download

        try:
            os.rename(tar_download, download_folder)
        except Exception:
            msg = "Cannot untar layer %s," % tar_download
            msg += " was there a problem with download?"
            bot.error(msg)
            sys.exit(1)
        return download_folder
Exemple #11
0
def change_tar_permissions(tar_file,
                           file_permission=None,
                           folder_permission=None):

    '''change_tar_permissions changes a permission if
    any member in a tarfile file does not have it
    :param file_path the path to the file
    :param file_permission: stat permission to use for files
    :param folder_permission: stat permission to use for folders
    '''
    tar = tarfile.open(tar_file, "r:gz")

    # Owner read, write (o+rw)
    if file_permission is None:
        file_permission = stat.S_IRUSR | stat.S_IWUSR

    # Owner read, write execute (o+rwx)
    if folder_permission is None:
        folder_permission = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR

    # Add owner write permission to all, not symlinks
    members = tar.getmembers()

    if len(members) > 0:

        bot.verbose("Fixing permission for %s" % tar_file)

        # Add all content objects to file
        fd, tmp_tar = tempfile.mkstemp(prefix=("%s.fixperm." % tar_file))
        os.close(fd)
        fixed_tar = tarfile.open(tmp_tar, "w:gz")

        for member in members:

            # add o+rwx for directories
            if member.isdir() and not member.issym():
                member.mode = folder_permission | member.mode
                extracted = tar.extractfile(member)
                fixed_tar.addfile(member, extracted)

            # add o+rw for plain files
            elif member.isfile() and not member.issym():
                member.mode = file_permission | member.mode
                extracted = tar.extractfile(member)
                fixed_tar.addfile(member, extracted)
            else:
                fixed_tar.addfile(member)

        fixed_tar.close()
        tar.close()

        # Rename the fixed tar to be the old name
        os.rename(tmp_tar, tar_file)
    else:
        tar.close()
        bot.warning("Tar file %s is empty, skipping." % tar_file)

    return tar_file
Exemple #12
0
def change_tar_permissions(tar_file,
                           file_permission=None,
                           folder_permission=None):
    '''change_tar_permissions changes a permission if
    any member in a tarfile file does not have it
    :param file_path the path to the file
    :param file_permission: stat permission to use for files
    :param folder_permission: stat permission to use for folders
    '''
    tar = tarfile.open(tar_file, "r:gz")

    # Owner read, write (o+rw)
    if file_permission is None:
        file_permission = stat.S_IRUSR | stat.S_IWUSR

    # Owner read, write execute (o+rwx)
    if folder_permission is None:
        folder_permission = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR

    # Add owner write permission to all, not symlinks
    members = tar.getmembers()

    if len(members) > 0:

        bot.verbose("Fixing permission for %s" % tar_file)

        # Add all content objects to file
        fd, tmp_tar = tempfile.mkstemp(prefix=("%s.fixperm." % tar_file))
        os.close(fd)
        fixed_tar = tarfile.open(tmp_tar, "w:gz")

        for member in members:

            # add o+rwx for directories
            if member.isdir() and not member.issym():
                member.mode = folder_permission | member.mode
                extracted = tar.extractfile(member)
                fixed_tar.addfile(member, extracted)

            # add o+rw for plain files
            elif member.isfile() and not member.issym():
                member.mode = file_permission | member.mode
                extracted = tar.extractfile(member)
                fixed_tar.addfile(member, extracted)
            else:
                fixed_tar.addfile(member)

        fixed_tar.close()
        tar.close()

        # Rename the fixed tar to be the old name
        os.rename(tmp_tar, tar_file)
    else:
        tar.close()
        bot.warning("Tar file %s is empty, skipping." % tar_file)

    return tar_file
Exemple #13
0
def SIZE(image,auth=None,contentfile=None):
    '''size is intended to be run before an import, to return to the contentfile a list of sizes
    (one per layer) corresponding with the layers that will be downloaded for image
    '''
    bot.debug("Starting Docker SIZE, will get size from manifest")
    bot.verbose("Docker image: %s" %image)
    client = DockerApiConnection(image=image,auth=auth)
    size = client.get_size()
    if contentfile is not None:
        write_file(contentfile,str(size),mode="w")
    return size 
Exemple #14
0
    def get_manifest(self, old_version=False, version=None):
        '''get_manifest should return an image manifest
        for a particular repo and tag.  The image details
        are extracted when the client is generated.
        :param old_version: return version 1
                            (for cmd/entrypoint), default False
        '''
        registry = self.registry
        if registry is None:
            registry = self.api_base

        # make sure we have a complete url
        registry = add_http(registry)

        base = "%s/%s/%s/%s/manifests" % (registry, self.api_version,
                                          self.namespace, self.repo_name)

        # First priority given to calling function
        if version is not None:
            base = "%s/%s" % (base, version)

        elif self.version is not None:
            base = "%s/%s" % (base, self.version)

        else:
            base = "%s/%s" % (base, self.repo_tag)
        bot.verbose("Obtaining manifest: %s" % base)

        headers = self.headers.copy()
        if old_version is True:
            headers['Accept'] = 'application/json'

        response = self.get(base, headers=headers)

        try:
            response = json.loads(response)

        except Exception:

            # If the call fails, give the user a list of acceptable tags
            tags = self.get_tags()
            print("\n".join(tags))
            repo_uri = "%s/%s:%s" % (self.namespace, self.repo_name,
                                     self.repo_tag)

            bot.error("Error getting manifest for %s, exiting." % repo_uri)
            sys.exit(1)

        # If we have errors, don't continue
        return self.check_errors(response)
Exemple #15
0
    def get_layer(self,image_id,download_folder=None,change_perms=False,return_tmp=False):
        '''get_layer will download an image layer (.tar.gz) to a specified download folder.
        :param download_folder: if specified, download to folder.
        Otherwise return response with raw data (not recommended)
        :param change_perms: change permissions additionally (default False to support 
        multiprocessing)
        :param return_tmp: If true, return the temporary file name (and don't rename to the file's final
        name). Default is False, should be True for multiprocessing that requires extra permission changes
        '''
        registry = self.registry
        if registry == None:
            registry = self.api_base
        registry = add_http(registry) # make sure we have a complete url

        # The <name> variable is the namespace/repo_name
        base = "%s/%s/%s/%s/blobs/%s" %(registry,self.api_version,self.namespace,self.repo_name,image_id)
        bot.verbose("Downloading layers from %s" %base)
    
        if download_folder is None:        
            download_folder = tempfile.mkdtemp()

        download_folder = "%s/%s.tar.gz" %(download_folder,image_id)

        # Update user what we are doing
        bot.debug("Downloading layer %s" %image_id)

        # Step 1: Download the layer atomically
        file_name = "%s.%s" %(download_folder,next(tempfile._get_candidate_names()))
        tar_download = self.download_atomically(url=base,
                                                file_name=file_name)
        bot.debug('Download of raw file (pre permissions fix) is %s' %tar_download)

        # Step 2: Fix Permissions?
        if change_perms:
            tar_download = change_tar_permissions(tar_download)

        if return_tmp is True:
            return tar_download

        try:
            os.rename(tar_download,download_folder)
        except:
            bot.error("Cannot untar layer %s, was there a problem with download?" %tar_download)
            sys.exit(1)
        return download_folder
Exemple #16
0
def parse_image_uri(image,
                    uri=None,
                    quiet=False,
                    default_registry=None,
                    default_namespace=None,
                    default_tag=None):
    '''parse_image_uri will parse a docker or shub uri and return
    a json structure with a registry, repo name, tag, namespace and version.
    Tag and version are optional, namespace is optional for docker:// uris.
    URIs are of this general form:
        myuri://[registry.com:port/][namespace/nested/]repo[:tag][@version]
    (parts in [] are optional)
    Parsing rules are slightly different if the uri is a docker:// uri:
    - registry must include a :port or a . in its name, else will be parsed
      as a namespace. For non-docker uris, instead, if there are three or
      more parts separated by /, the first one is taken to be the registry
    - namespace can be empty if a registry is specified, else default
      namespace will be used (e.g. docker://registry.com/repo:tag).
      For non-docker uris, namespace cannot be empty and default will be used

    :param image: the string provided on command line for
                  the image name, eg: ubuntu:latest or
                  docker://local.registry/busybox@12345
    :param uri: the uri type (eg, docker://), default autodetects
    ::note uri is maintained as variable so we have some control over allowed
    :param quiet: If True, don't show verbose messages with the parsed values
    :default_registry: Which registry to use if image doesn't contain one.
                       if None, use defaults.REGISTRY
    :default_namespace: Which namespace to use if image doesn't contain one.
                       if None, use defaults.NAMESPACE. Also, check out the
                       note above about docker:// and empty namespaces.
    :default_tag: Which tag to use if image doesn't contain one.
                       if None, use defaults.REPO_TAG
    :returns parsed: a json structure with repo_name, repo_tag, and namespace
    '''

    # Default to most common use case, Docker
    if default_registry is None:
        default_registry = DOCKER_API_BASE

    if default_namespace is None:
        default_namespace = NAMESPACE

    if default_tag is None:
        default_tag = TAG

    # if user gave custom registry / namespace, make them the default
    if CUSTOM_NAMESPACE is not None:
        default_namespace = CUSTOM_NAMESPACE

    if CUSTOM_REGISTRY is not None:
        default_registry = CUSTOM_REGISTRY

    # candidate regex for matching, in order of preference
    uri_regexes = [_reduced_uri_no_ns_re, _default_uri_re]

    # Be absolutely sure there are no comments
    image = image.split('#')[0]

    if not uri:
        uri = get_image_uri(image, quiet=True)

    # docker images require slightly different rules
    if uri == "docker://":
        uri_regexes = [_docker_uri_re]

    image = remove_image_uri(image, uri)

    for r in uri_regexes:
        match = r.match(image)
        if match:
            break

    if not match:
        bot.error('Could not parse image "%s"! Exiting.' % image)
        sys.exit(1)

    registry = match.group('registry')
    namespace = match.group('namespace')
    repo_name = match.group('repo')
    repo_tag = match.group('tag')
    version = match.group('version')

    if namespace:
        # strip trailing /
        namespace = namespace.rstrip('/')

    # repo_name is required and enforced by the re (in theory)
    # if not provided, re should not match
    assert (repo_name)

    # replace empty fields with defaults
    if not namespace:
        # for docker, if a registry was specified, don't
        # inject a namespace in between
        if registry and uri == "docker://":
            namespace = ""
        else:
            namespace = default_namespace
    if not registry:
        registry = default_registry
    if not repo_tag:
        repo_tag = default_tag
    # version is not mandatory, don't check that

    if not quiet:
        bot.verbose("Registry: %s" % registry)
        bot.verbose("Namespace: %s" % namespace)
        bot.verbose("Repo Name: %s" % repo_name)
        bot.verbose("Repo Tag: %s" % repo_tag)
        bot.verbose("Version: %s" % version)

    parsed = {
        'registry': registry,
        'namespace': namespace,
        'repo_name': repo_name,
        'repo_tag': repo_tag,
        'version': version
    }

    return parsed
Exemple #17
0
def IMPORT(image, auth=None, layerfile=None):
    '''IMPORT is the main script that will obtain docker layers,
    runscript information (either entrypoint or cmd), and environment
    and return a list of tarballs to extract into the image
    :param auth: if needed, an authentication header (default None)
    :param layerfile: The file to write layers to extract into
    '''
    bot.debug("Starting Docker IMPORT, includes env, runscript, and metadata.")
    bot.verbose("Docker image: %s" % image)

    # Does the user want to override default of using ENTRYPOINT?
    if INCLUDE_CMD:
        bot.verbose2("Specified Docker CMD as %runscript.")
    else:
        bot.verbose2("Specified Docker ENTRYPOINT as %runscript.")

    # Input Parsing ----------------------------
    # Parse image name, repo name, and namespace
    client = DockerApiConnection(image=image, auth=auth)

    docker_image_uri = "Docker image path: %s" % client.assemble_uri("/")
    bot.info(docker_image_uri)

    # IMAGE METADATA -------------------------------------------
    # Use Docker Registry API (version 2.0) to get images ids, manifest

    images = client.get_images()

    #  DOWNLOAD LAYERS -------------------------------------------
    # Each is a .tar.gz file, obtained from registry with curl

    # Get the cache (or temporary one) for docker
    cache_base = get_cache(subfolder="docker")
    download_client = MultiProcess()

    # Generate a queue of tasks to run with MultiProcess
    layers = []
    tasks = []
    for ii in range(len(images)):
        image_id = images[ii]
        targz = "%s/%s.tar.gz" % (cache_base, image_id)
        if not os.path.exists(targz):
            tasks.append((client, image_id, cache_base))
        layers.append(targz)

    # Does the user want to change permissions of tar?
    func2 = None
    if PLUGIN_FIXPERMS:
        func2 = change_permissions

    if len(tasks) > 0:
        download_layers = download_client.run(func=download_layer,
                                              func2=func2,
                                              tasks=tasks)

    # Get Docker runscript
    runscript = extract_runscript(manifest=client.manifestv1,
                                  includecmd=INCLUDE_CMD)

    # Add the environment export
    tar_file = extract_metadata_tar(client.manifestv1,
                                    client.assemble_uri(),
                                    runscript=runscript)

    bot.verbose2('Tar file with Docker env and labels: %s' % tar_file)

    # Write all layers to the layerfile
    if layerfile is not None:
        bot.verbose3("Writing Docker layers files to %s" % layerfile)
        write_file(layerfile, "\n".join(layers), mode="w")
        if tar_file is not None:
            write_file(layerfile, "\n%s" % tar_file, mode="a")

    # Return additions dictionary
    additions = {"layers": layers,
                 "image": image,
                 "manifest": client.manifest,
                 "manifestv1": client.manifestv1,
                 "cache_base": cache_base,
                 "metadata": tar_file}

    bot.debug("*** FINISHING DOCKER IMPORT PYTHON PORTION ****\n")

    return additions
Exemple #18
0
def IMPORT(image, auth=None, layerfile=None):
    '''IMPORT is the main script that will obtain docker layers,
    runscript information (either entrypoint or cmd), and environment
    and return a list of tarballs to extract into the image
    :param auth: if needed, an authentication header (default None)
    :param layerfile: The file to write layers to extract into
    '''
    bot.debug("Starting Docker IMPORT, includes env, runscript, and metadata.")
    bot.verbose("Docker image: %s" % image)

    # Does the user want to override default of using ENTRYPOINT?
    if INCLUDE_CMD:
        bot.verbose2("Specified Docker CMD as %runscript.")
    else:
        bot.verbose2("Specified Docker ENTRYPOINT as %runscript.")

    # Input Parsing ----------------------------
    # Parse image name, repo name, and namespace
    client = DockerApiConnection(image=image, auth=auth)

    docker_image_uri = "Docker image path: %s" % client.assemble_uri("/")
    bot.info(docker_image_uri)

    # IMAGE METADATA -------------------------------------------
    # Use Docker Registry API (version 2.0) to get images ids, manifest

    images = client.get_images()

    #  DOWNLOAD LAYERS -------------------------------------------
    # Each is a .tar.gz file, obtained from registry with curl

    # Get the cache (or temporary one) for docker
    cache_base = get_cache(subfolder="docker")
    download_client = MultiProcess()

    # Generate a queue of tasks to run with MultiProcess
    layers = []
    tasks = []
    for ii in range(len(images)):
        image_id = images[ii]
        targz = "%s/%s.tar.gz" % (cache_base, image_id)
        if not os.path.exists(targz):
            tasks.append((client, image_id, cache_base))
        layers.append(targz)

    # Does the user want to change permissions of tar?
    func2 = None
    if PLUGIN_FIXPERMS:
        func2 = change_permissions

    if len(tasks) > 0:
        download_layers = download_client.run(func=download_layer,
                                              func2=func2,
                                              tasks=tasks)

    # Get Docker runscript
    runscript = extract_runscript(manifest=client.manifestv1,
                                  includecmd=INCLUDE_CMD)

    # Add the environment export
    tar_file = extract_metadata_tar(client.manifestv1,
                                    client.assemble_uri(),
                                    runscript=runscript)

    bot.verbose2('Tar file with Docker env and labels: %s' % tar_file)

    # Write all layers to the layerfile
    if layerfile is not None:
        bot.verbose3("Writing Docker layers files to %s" % layerfile)
        write_file(layerfile, "\n".join(layers), mode="w")
        if tar_file is not None:
            write_file(layerfile, "\n%s" % tar_file, mode="a")

    # Return additions dictionary
    additions = {
        "layers": layers,
        "image": image,
        "manifest": client.manifest,
        "manifestv1": client.manifestv1,
        "cache_base": cache_base,
        "metadata": tar_file
    }

    bot.debug("*** FINISHING DOCKER IMPORT PYTHON PORTION ****\n")

    return additions
Exemple #19
0
def parse_image_uri(image, uri=None, quiet=False):
    '''parse_image_uri will return a json structure with a registry, 
    repo name, tag, and namespace, intended for Docker.
    :param image: the string provided on command line for the image name, eg: ubuntu:latest
    :param uri: the uri (eg, docker:// to remove), default uses ""
    ::note uri is maintained as a variable so we have some control over allowed
    :returns parsed: a json structure with repo_name, repo_tag, and namespace
    '''

    if uri == None:
        uri = ""

    # Be absolutely sure there are not comments
    image = image.split('#')[0]

    # Get rid of any uri, and split the tag
    image = image.replace(uri, '')

    # Does the uri have a digest or Github tag (version)?
    image = image.split('@')
    version = None
    if len(image) == 2:
        version = image[1]

    image = image[0]
    image = image.split(':')

    # If there are three parts, we have port and tag
    if len(image) == 3:
        repo_tag = image[2]
        image = "%s:%s" % (image[0], image[1])

    # If there are two parts, we have port or tag
    elif len(image) == 2:
        # If there isn't a slash in second part, we have a tag
        if image[1].find("/") == -1:
            repo_tag = image[1]
            image = image[0]
        # Otherwise we have a port and we merge the path
        else:
            image = "%s:%s" % (image[0], image[1])
            repo_tag = default_tag
    else:
        image = image[0]
        repo_tag = default_tag

    # Now look for registry, namespace, repo
    image = image.split('/')

    if len(image) == 3:
        registry = image[0]
        namespace = image[1]
        repo_name = image[2]

    elif len(image) == 2:
        registry = default_registry
        namespace = image[0]
        repo_name = image[1]

    else:
        registry = default_registry
        namespace = default_namespace
        repo_name = image[0]

    if not quiet:
        bot.verbose("Registry: %s" % registry)
        bot.verbose("Namespace: %s" % namespace)
        bot.verbose("Repo Name: %s" % repo_name)
        bot.verbose("Repo Tag: %s" % repo_tag)
        bot.verbose("Version: %s" % version)

    parsed = {
        'registry': registry,
        'namespace': namespace,
        'repo_name': repo_name,
        'repo_tag': repo_tag
    }

    # No field should be empty
    for fieldname, value in parsed.items():
        if len(value) == 0:
            bot.error("%s found empty, check uri! Exiting." % value)
            sys.exit(1)

    # Version is not required
    parsed['version'] = version

    return parsed
Exemple #20
0
def parse_image_uri(image,uri=None,quiet=False):
    '''parse_image_uri will return a json structure with a registry, 
    repo name, tag, and namespace, intended for Docker.
    :param image: the string provided on command line for the image name, eg: ubuntu:latest
    :param uri: the uri (eg, docker:// to remove), default uses ""
    ::note uri is maintained as a variable so we have some control over allowed
    :returns parsed: a json structure with repo_name, repo_tag, and namespace
    '''

    if uri == None:
        uri = ""

    # Be absolutely sure there are not comments
    image = image.split('#')[0]
    
    # Get rid of any uri, and split the tag
    image = image.replace(uri,'')

    # Does the uri have a digest or Github tag (version)?
    image = image.split('@')
    version = None
    if len(image) == 2:
        version = image[1]

    image = image[0]
    image = image.split(':')

    # If there are three parts, we have port and tag
    if len(image) == 3:
        repo_tag = image[2]
        image = "%s:%s" %(image[0],image[1])

    # If there are two parts, we have port or tag
    elif len(image) == 2:
        # If there isn't a slash in second part, we have a tag
        if image[1].find("/") == -1:
            repo_tag = image[1]
            image = image[0]
        # Otherwise we have a port and we merge the path
        else:
            image = "%s:%s" %(image[0],image[1])
            repo_tag = default_tag
    else:
        image = image[0]
        repo_tag = default_tag

    # Now look for registry, namespace, repo
    image = image.split('/')

    if len(image) == 3:
        registry = image[0]
        namespace = image[1]
        repo_name = image[2]

    elif len(image) == 2:
        registry = default_registry
        namespace = image[0]
        repo_name = image[1]

    else:
        registry = default_registry
        namespace = default_namespace
        repo_name = image[0]

    if not quiet:
        bot.verbose("Registry: %s" %registry)
        bot.verbose("Namespace: %s" %namespace)
        bot.verbose("Repo Name: %s" %repo_name)
        bot.verbose("Repo Tag: %s" %repo_tag)
        bot.verbose("Version: %s" %version)

    parsed = {'registry':registry,
              'namespace':namespace, 
              'repo_name':repo_name,
              'repo_tag':repo_tag }

    # No field should be empty
    for fieldname,value in parsed.items():
        if len(value) == 0:
            bot.error("%s found empty, check uri! Exiting." %value)
            sys.exit(1)

    # Version is not required
    parsed['version'] = version 

    return parsed