def dockerfile_to_singularity(dockerfile_path, output_dir=None):
    '''dockerfile_to_singularity will return a Singularity build file based on
    a provided Dockerfile. If output directory is not specified, the string
    will be returned. Otherwise, a file called Singularity will be written to 
    output_dir
    :param dockerfile_path: the path to the Dockerfile
    :param output_dir: the output directory to write the Singularity file to
    '''
    build_file = None

    if os.path.basename(dockerfile_path) == "Dockerfile":

        try:
            spec = read_file(dockerfile_path)
            # Use a common mapping
            mapping = get_mapping()
            # Put into dict of keys (section titles) and list of commands (values)
            sections = organize_sections(lines=spec, mapping=mapping)
            # We have to, by default, add the Docker bootstrap
            sections["bootstrap"] = ["docker"]
            # Put into one string based on "order" variable in mapping
            build_file = print_sections(sections=sections, mapping=mapping)
            if output_dir != None:
                write_file("%s/Singularity" % (output_dir), build_file)
                print("Singularity spec written to %s" % (output_dir))
            return build_file

        except:
            bot.logger.error("Error generating Dockerfile from %s.",
                             dockerfile_path)

    # If we make it here, something didn't work
    bot.logger.error("Could not find %s.", dockerfile_path)
    return build_file
예제 #2
0
def get_build_template(template_name, params=None, to_file=None):
    '''get_build template returns a string or file for a particular build template, which is
    intended to build a version of a Singularity image on a cloud resource.
    :param template_name: the name of the template to retrieve in build/scripts
    :param params: (if needed) a dictionary of parameters to substitute in the file
    :param to_file: if defined, will write to file. Default returns string.
    '''
    base = get_installdir()
    template_folder = "%s/build/scripts" % (base)
    template_file = "%s/%s" % (template_folder, template_name)
    if os.path.exists(template_file):
        bot.debug("Found template %s" % template_file)

        # Implement when needed - substitute params here
        # Will need to read in file instead of copying below
        # if params != None:

        if to_file is not None:
            shutil.copyfile(template_file, to_file)
            bot.debug("Template file saved to %s" % to_file)
            return to_file

        # If the user wants a string
        content = ''.join(read_file(template_file))
        return content

    else:
        bot.warning("Template %s not found." % template_file)
예제 #3
0
    def test_write_read_files(self):
        '''test_write_read_files will test the functions write_file and read_file
        '''
        print("Testing utils.write_file...")
        from singularity.utils import write_file
        import json
        tmpfile = tempfile.mkstemp()[1]
        os.remove(tmpfile)
        write_file(tmpfile,"hello!")
        self.assertTrue(os.path.exists(tmpfile))        

        print("Testing utils.read_file...")
        from singularity.utils import read_file
        content = read_file(tmpfile)[0]
        self.assertEqual("hello!",content)

        from singularity.utils import write_json
        print("Testing utils.write_json...")
        print("...Case 1: Providing bad json")
        bad_json = {"Wakkawakkawakka'}":[{True},"2",3]}
        tmpfile = tempfile.mkstemp()[1]
        os.remove(tmpfile)        
        with self.assertRaises(TypeError) as cm:
            write_json(bad_json,tmpfile)

        print("...Case 2: Providing good json")        
        good_json = {"Wakkawakkawakka":[True,"2",3]}
        tmpfile = tempfile.mkstemp()[1]
        os.remove(tmpfile)
        write_json(good_json,tmpfile)
        with open(tmpfile,'r') as filey:
            content = json.loads(filey.read())
        self.assertTrue(isinstance(content,dict))
        self.assertTrue("Wakkawakkawakka" in content)
예제 #4
0
def package(image_path,
            spec_path=None,
            output_folder=None,
            remove_image=False,
            verbose=False,
            S=None):
    '''generate a zip (including the image) to a user specified output_folder.
    :param image_path: full path to singularity image file
    :param runscript: if True, will extract runscript to include in package as runscript
    :param software: if True, will extract files.txt and folders.txt to package
    :param remove_image: if True, will not include original image in package (default,False)
    :param verbose: be verbose when using singularity --export (default,False)
    :param S: the Singularity object (optional) will be created if not required.
    '''

    # Run create image and bootstrap with Singularity command line tool.
    S = Singularity(debug=verbose)

    file_obj, tar = get_image_tar(image_path, S=S)

    members = tar.getmembers()
    image_name, ext = os.path.splitext(os.path.basename(image_path))
    zip_name = "%s.zip" % (image_name.replace(" ", "_"))

    # Include the image in the package?
    to_package = dict()
    if not remove_image:
        to_package["files"] = [image_path]

    # If the specfile is provided, it should also be packaged
    if spec_path is not None:
        singularity_spec = "".join(read_file(spec_path))
        to_package['Singularity'] = singularity_spec
        to_package["VERSION"] = get_image_file_hash(image_path)

    try:
        inspection = S.inspect(image_path)
        to_package["inspect.json"] = inspection
        inspection = json.loads(inspection)
        to_package['runscript'] = inspection['data']['attributes']['runscript']
    except:
        bot.warning("Trouble extracting container metadata with inspect.")

    bot.info("Adding software list to package.")
    files = [x.path for x in members if x.isfile()]
    folders = [x.path for x in members if x.isdir()]
    to_package["files.txt"] = files
    to_package["folders.txt"] = folders

    # Do zip up here - let's start with basic structures
    zipfile = zip_up(to_package,
                     zip_name=zip_name,
                     output_folder=output_folder)
    bot.debug("Package created at %s" % (zipfile))

    if not delete_image_tar(file_obj, tar):
        bot.warning("Could not clean up temporary tarfile.")

    # return package to user
    return zipfile
예제 #5
0
def get_build_template(template_name,params=None,to_file=None):
    '''get_build template returns a string or file for a particular build template, which is
    intended to build a version of a Singularity image on a cloud resource.
    :param template_name: the name of the template to retrieve in build/scripts
    :param params: (if needed) a dictionary of parameters to substitute in the file
    :param to_file: if defined, will write to file. Default returns string.
    '''
    base = get_installdir()
    template_folder = "%s/build/scripts" %(base)
    template_file = "%s/%s" %(template_folder,template_name)
    if os.path.exists(template_file):
        bot.debug("Found template %s" %template_file)

        # Implement when needed - substitute params here
        # Will need to read in file instead of copying below
        # if params != None:
 
        if to_file is not None:
            shutil.copyfile(template_file,to_file)
            bot.debug("Template file saved to %s" %to_file)
            return to_file

        # If the user wants a string
        content = ''.join(read_file(template_file)) 
        return content


    else:
        bot.warning("Template %s not found." %template_file)
예제 #6
0
def main(args, parser, subparser):

    if args.recipe is None:
        subparser.print_help()
        bot.newline()
        print("Please specify creating a recipe with --recipe")
        sys.exit(0)

    # Output folder will be pwd if not specified
    output_folder = os.getcwd()
    if args.outfolder is not None:
        output_folder = os.getcwd()

    bootstrap = ''
    if args.bootstrap is not None:
        bootstrap = args.bootstrap
        bot.debug("bootstrap: %s" % bootstrap)

    bootstrap_from = ''
    if args.bootstrap_from is not None:
        bootstrap_from = args.bootstrap_from
        bot.debug("from: %s" % bootstrap_from)

    template = "Singularity"
    output_file = template
    app = ''
    if args.app is not None:
        app = args.app.lower()
        template = "Singularity.app"
        output_file = "Singularity.%s" % app

    input_file = "%s/cli/app/templates/recipes/%s" % (get_installdir(),
                                                      template)
    output_file = "%s/%s" % (output_folder, output_file)

    if os.path.exists(output_file):
        ext = str(uuid.uuid4())[0:4]
        output_file = "%s.%s" % (output_file, ext)

    # Read the file, make substitutions
    contents = read_file(input_file, readlines=False)

    # Replace all occurrences of app
    contents = contents.replace('{{ app }}', app)
    contents = contents.replace('{{ bootstrap }}', bootstrap)
    contents = contents.replace('{{ from }}', bootstrap_from)

    write_file(output_file, contents)
    bot.info("Output file written to %s" % output_file)
예제 #7
0
def get_template(template_name, fields=None):
    '''get_template will return a template in the template folder,
    with some substitutions (eg, {'{{ graph | safe }}':"fill this in!"}
    '''
    template = None
    if not template_name.endswith('.html'):
        template_name = "%s.html" % (template_name)
    here = "%s/templates" % (get_installdir())
    template_path = "%s/%s" % (here, template_name)
    if os.path.exists(template_path):
        template = ''.join(read_file(template_path))
    if fields is not None:
        for tag, sub in fields.items():
            template = template.replace(tag, sub)
    return template
예제 #8
0
def get_template(template_name,fields=None):
    '''get_template will return a template in the template folder,
    with some substitutions (eg, {'{{ graph | safe }}':"fill this in!"}
    '''
    template = None
    if not template_name.endswith('.html'):
        template_name = "%s.html" %(template_name)
    here = "%s/cli/app/templates" %(get_installdir())
    template_path = "%s/%s" %(here,template_name)
    if os.path.exists(template_path):
        template = ''.join(read_file(template_path))
    if fields is not None:
        for tag,sub in fields.items():
            template = template.replace(tag,sub)
    return template
예제 #9
0
def detect_language(runscript):
    '''detect_language will use pygments to detect the language of a run script
    :param runscript: the full path to the run script, or string of runscript itself
    '''
    if os.path.exists(runscript):
        content = read_file(runscript)
    else:
        content = runscript
    try:
        language = guess_lexer(''.join(content))
        if language.name == "Python":
            return "python"
        else:
            print("Language %s is not yet supported." %(language.name))
    except ClassNotFound:
        print("Cannot detect language.")
    return None    
예제 #10
0
def package(image_path,
            spec_path=None,
            output_folder=None,
            runscript=True,
            software=True,
            remove_image=False,
            verbose=False,
            S=None,
            sudopw=None,
            old_version=False):
    '''package will take an image and generate a zip (including the image
    to a user specified output_folder.
    :param image_path: full path to singularity image file
    :param runscript: if True, will extract runscript to include in package as runscript
    :param software: if True, will extract files.txt and folders.txt to package
    :param remove_image: if True, will not include original image in package (default,False)
    :param verbose: be verbose when using singularity --export (default,False)
    :param S: the Singularity object (optional) will be created if not required.
    '''
    # Run create image and bootstrap with Singularity command line tool.
    if S == None:
        if sudopw != None:
            S = Singularity(sudopw=sudopw, debug=verbose)
        else:
            S = Singularity(
                debug=verbose)  # This command will ask the user for sudo

    # Singularity < version 2.3
    if old_version == False:
        file_obj, tar = get_memory_tar(image_path)

    # Singularity 2.3 and up
    else:
        tmptar = S.export(image_path=image_path, old_version=True)
        tar = tarfile.open(tmptar)

    members = tar.getmembers()
    image_name = os.path.basename(image_path)
    zip_name = "%s.zip" % (image_name.replace(" ", "_"))

    # Include the image in the package?
    if remove_image:
        to_package = dict()
    else:
        to_package = {"files": [image_path]}

    # If the specfile is provided, it should also be packaged
    if spec_path is not None:
        singularity_spec = "".join(read_file(spec_path))
        to_package['Singularity'] = singularity_spec

    # Package the image with an sha1, identical standard, as VERSION
    if old_version == False:
        hashes = get_image_hashes(image_path)
        to_package["HASHES"] = hashes
        to_package["VERSION"] = hashes['IDENTICAL']
    else:
        to_package["VERSION"] = get_image_file_hash(image_path)

    # Look for runscript
    if runscript is True:
        try:
            to_package["runscript"] = extract_content(image_path,
                                                      './singularity',
                                                      cli=S)
            bot.logger.debug("Found runscript.")
        except KeyError:
            bot.logger.warning("No runscript found")

    if software == True:
        bot.logger.info("Adding software list to package.")
        files = [x.path for x in members if x.isfile()]
        folders = [x.path for x in members if x.isdir()]
        to_package["files.txt"] = files
        to_package["folders.txt"] = folders

    # Do zip up here - let's start with basic structures
    zipfile = zip_up(to_package,
                     zip_name=zip_name,
                     output_folder=output_folder)
    bot.logger.debug("Package created at %s" % (zipfile))

    if old_version == False:
        file_obj.close()

    # return package to user
    return zipfile