示例#1
0
    def test_codegen_success(codegen_gen_py_inputs, popen_helper):
        gen_py = codegen_gen_py_inputs
        stderr_ret = (
            '[main] INFO io.swagger.parser.Swagger20Parser - reading from'
            ' swagger.json'
            '[main] INFO io.swagger.codegen.AbstractGenerator - writing file'
            ' .dvp-gen-output/swagger_server/generated/test_gen_file.py')
        popen_helper.set_popen_output(0, stderr=stderr_ret)

        codegen.generate_python(gen_py.name, gen_py.source_dir,
                                gen_py.plugin_content_dir, gen_py.schema_dict)

        assert popen_helper.stdout_input == subprocess.PIPE
        assert popen_helper.stderr_input == subprocess.PIPE
        assert os.path.exists(popen_helper.swagger_file)
        assert popen_helper.package_name == codegen.CODEGEN_PACKAGE
        assert popen_helper.module_name == codegen.CODEGEN_MODULE
        expected_output_dir = os.path.join(gen_py.plugin_content_dir,
                                           const.OUTPUT_DIR_NAME)
        assert popen_helper.output_dir == expected_output_dir

        # Validate that the "generated" file were copied.
        util_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE,
                                 'util.py')
        init_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE,
                                 '__init__.py')

        gen_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE,
                                codegen.CODEGEN_MODULE,
                                TestCodegen.TEST_GEN_FILE)

        assert os.path.exists(util_file)
        assert os.path.exists(init_file)
        assert os.path.exists(gen_file)
def init(root, ingestion_strategy, name, host_type):
    """
    Creates a valid plugin in a given directory. The plugin created will be
    able to be built and uploaded immediately.

    This command is designed to help novice plugin developers. There are
    decisions made, such as what the entry point file looks like, in order to
    make it easier for authors to get started. The command is expected to be
    used by experienced developers, but they are not the primary audience.

    Args:
        root (str): The path of the plugin's root directory
        ingestion_strategy (str): The plugin type. Either DIRECT or STAGED
        name (str): The name of the plugin to display.
        host_type (list of str): The host type supported by the plugin
    """
    logger.info('Initializing directory: %s', root)
    logger.debug(
        'init parameters: %s', {
            'Root': root,
            'Ingestion Strategy': ingestion_strategy,
            'Name': name,
            'Host Types': host_type
        })

    # Files paths based on 'root' to be used throughout
    src_dir_path = os.path.join(root, DEFAULT_SRC_DIRECTORY)
    config_file_path = os.path.join(root, DEFAULT_PLUGIN_CONFIG_FILE)
    schema_file_path = os.path.join(root, DEFAULT_SCHEMA_FILE)
    entry_point_file_path = os.path.join(src_dir_path,
                                         DEFAULT_ENTRY_POINT_FILE)

    # Make sure nothing is overwritten
    file_util.validate_paths_do_not_exist(config_file_path, schema_file_path,
                                          src_dir_path)

    # Make an UUID for the plugin
    plugin_id = str(uuid.uuid4())
    logger.debug("Using %s as the plugin id.", plugin_id)

    # if name is not provided the name will be equal to plugin_id.
    if not name:
        name = plugin_id

    #
    # Some magic to get the yaml module to maintain the order when dumping
    # an OrderedDict
    #
    yaml.add_representer(
        OrderedDict, lambda dumper, data: dumper.represent_mapping(
            'tag:yaml.org,2002:map', data.items()))

    logger.debug("Using %s as the plugin's entry point.", DEFAULT_ENTRY_POINT)
    try:
        #
        # Create the source directory. We've already validated that this
        # directory doesn't exist.
        #
        logger.info('Creating source directory at %r.', src_dir_path)
        os.mkdir(src_dir_path)

        #
        # Copy the schema file template into the root directory. The schema
        # file is static and doesn't depend on any input so it can just be
        # copied. By copying we can also avoid dealing with ordering issues.
        #
        logger.info('Writing schema file at %s.', schema_file_path)
        shutil.copyfile(SCHEMA_TEMPLATE_PATH, schema_file_path)

        # Read and valida the schema file
        result = plugin_util.read_and_validate_schema_file(
            schema_file_path, False)

        # Generate the definitions based on the schema file
        codegen.generate_python(name, src_dir_path,
                                os.path.dirname(config_file_path),
                                result.plugin_schemas)

        #
        # Create the plugin config file. The config file relies on input from
        # the user, so it's easier to deal with a dictionary than a file. This
        # must be done only after both the schema file and src dir have been
        # created since the paths need to exist.
        #
        logger.info('Writing config file at %s.', config_file_path)
        with open(config_file_path, 'w+') as f:
            config = _get_default_plugin_config(plugin_id, ingestion_strategy,
                                                name, DEFAULT_ENTRY_POINT,
                                                DEFAULT_SRC_DIRECTORY,
                                                DEFAULT_SCHEMA_FILE, host_type)
            yaml.dump(config, f, default_flow_style=False)

        #
        # Copy the entry point template into the root directory. The entry
        # point file is static and doesn't depend on any input so it can just
        # be copied.
        #
        logger.info('Writing entry file at %s.', entry_point_file_path)
        with open(entry_point_file_path, 'w+') as f:
            entry_point_content = _get_entry_point_contents(
                plugin_id, ingestion_strategy, host_type)
            f.write(entry_point_content)

    except Exception as e:
        logger.debug('Attempting to cleanup after failure. %s', e)
        file_util.delete_paths(config_file_path, schema_file_path,
                               src_dir_path)
        raise exceptions.UserError(
            'Failed to initialize plugin directory {}: {}.'.format(root, e))
示例#3
0
def build(plugin_config, upload_artifact, generate_only, skip_id_validation):
    """This builds the plugin using the configurations provided in config yaml
    file provided as input. It reads schemas and source code from the files
    given in yaml file, generates an encoded string of zip of source code,
    prepares plugin json output file that can be used by upload command later.

    Args:
        plugin_config: Plugin config file used for building plugin.
        upload_artifact: The file to which output of build  is written to.
        generate_only: Only generate python classes from schema definitions.
        skip_id_validation: Skip validation of the plugin id.
    """
    logger.debug(
        "Build parameters include plugin_config: %s, upload_artifact: %s,"
        " generate_only: %s",
        plugin_config,
        upload_artifact,
        generate_only,
    )

    # Read content of the plugin config  file provided and perform validations
    logger.info("Reading and validating plugin config file %s", plugin_config)
    try:
        result = plugin_util.read_and_validate_plugin_config_file(
            plugin_config, not generate_only, False, skip_id_validation)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    plugin_config_content = result.plugin_config_content
    logger.debug("plugin config file content is : %s",
                 result.plugin_config_content)

    schema_file = plugin_util.get_schema_file_path(
        plugin_config, plugin_config_content["schemaFile"])

    # Read schemas from the file provided in the config and validate them
    logger.info("Reading and validating schemas from %s", schema_file)

    try:
        result = plugin_util.read_and_validate_schema_file(
            schema_file, not generate_only)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    schemas = result.plugin_schemas
    logger.debug("schemas found: %s", schemas)

    # Resolve the paths for source directory and schema file
    src_dir = file_util.get_src_dir_path(plugin_config,
                                         plugin_config_content["srcDir"])
    logger.debug("Source directory path resolved is %s", src_dir)

    #
    # Call directly into codegen to generate the python classes and make sure
    # the ones we zip up are up to date with the schemas.
    #
    try:
        codegen.generate_python(
            plugin_config_content["name"],
            src_dir,
            os.path.dirname(plugin_config),
            schemas,
        )
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    if generate_only:
        #
        # If the generate_only flag is set then just return after generation
        # has happened.
        #
        logger.info("Generating python code only. Skipping artifact build.")
        return

    #
    # Validate the plugin config content by importing the module
    # and check the entry point as well. Returns a manifest on
    # successful validation.
    #
    try:
        result = plugin_util.get_plugin_manifest(plugin_config,
                                                 plugin_config_content,
                                                 not generate_only,
                                                 skip_id_validation)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    plugin_manifest = {}
    if result:
        plugin_manifest = result.plugin_manifest
        if result.warnings:
            warning_msg = util_classes.MessageUtils.warning_msg(
                result.warnings)
            logger.warn("{}\n{} Warning(s). {} Error(s).".format(
                warning_msg, len(result.warnings["warning"]), 0))

    # Prepare the output artifact.
    try:
        plugin_output = prepare_upload_artifact(plugin_config_content, src_dir,
                                                schemas, plugin_manifest)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    # Write it to upload_artifact as json.
    try:
        generate_upload_artifact(upload_artifact, plugin_output)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    logger.info("Successfully generated artifact file at %s.", upload_artifact)

    logger.warn("\nBUILD SUCCESSFUL.")
示例#4
0
def build(plugin_config,
          upload_artifact,
          generate_only,
          skip_id_validation,
          local_vsdk_root=None):
    """This builds the plugin using the configurations provided in config yaml
    file provided as input. It reads schemas and source code from the files
    given in yaml file, generates an encoded string of zip of source code,
    prepares plugin json output file that can be used by upload command later.

    Args:
        plugin_config: Plugin config file used for building plugin.
        upload_artifact: The file to which output of build  is written to.
        generate_only: Only generate python classes from schema definitions.
        skip_id_validation: Skip validation of the plugin id.
        local_vsdk_root: The local path to the root of the Virtualization SDK
            repository.
    """
    logger.debug(
        'Build parameters include plugin_config: %s, upload_artifact: %s,'
        ' generate_only: %s', plugin_config, upload_artifact, generate_only)

    if local_vsdk_root:
        local_vsdk_root = os.path.expanduser(local_vsdk_root)

    # Read content of the plugin config  file provided and perform validations
    logger.info('Validating plugin config file %s', plugin_config)
    try:
        result = plugin_util.validate_plugin_config_file(
            plugin_config, not generate_only, skip_id_validation)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    plugin_config_content = result.plugin_config_content
    logger.debug('plugin config file content is : %s',
                 result.plugin_config_content)

    schema_file = plugin_util.get_schema_file_path(
        plugin_config, plugin_config_content['schemaFile'])

    # Read schemas from the file provided in the config and validate them
    logger.info('Validating schemas from %s', schema_file)

    try:
        result = plugin_util.validate_schema_file(schema_file,
                                                  not generate_only)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    schemas = result.plugin_schemas
    logger.debug('schemas found: %s', schemas)

    # Resolve the paths for source directory and schema file
    src_dir = file_util.get_src_dir_path(plugin_config,
                                         plugin_config_content['srcDir'])
    logger.debug('Source directory path resolved is %s', src_dir)

    #
    # Call directly into codegen to generate the python classes and make sure
    # the ones we zip up are up to date with the schemas.
    #
    try:
        codegen.generate_python(plugin_config_content['name'], src_dir,
                                os.path.dirname(plugin_config), schemas)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    if generate_only:
        #
        # If the generate_only flag is set then just return after generation
        # has happened.
        #
        logger.info('Generating python code only. Skipping artifact build.')
        return

    #
    # Validate the plugin config content by importing the module
    # and check the entry point as well. Returns a manifest on
    # successful validation.
    #
    try:
        result = plugin_util.get_plugin_manifest(plugin_config,
                                                 plugin_config_content,
                                                 not generate_only,
                                                 skip_id_validation)
    except (exceptions.UserError, exceptions.SDKToolingError) as err:
        raise exceptions.BuildFailedError(err)

    plugin_manifest = {}
    if result:
        plugin_manifest = result.plugin_manifest

    #
    # Setup a build directory for the plugin in its root. Dependencies are
    # packaged with the plugin and should not be installed into the original
    # source directory.
    #
    root = os.path.dirname(plugin_config)
    build_dir = os.path.join(root, BUILD_DIR_NAME)
    build_src_dir = os.path.join(build_dir, os.path.basename(src_dir))

    # Copy everything from the source directory into the build directory.
    file_util.clean_copy(src_dir, build_src_dir)

    # Install dependencies in the plugin's source root in the build directory.
    plugin_dependency_util.install_deps(build_src_dir,
                                        local_vsdk_root=local_vsdk_root)

    # Prepare the output artifact.
    try:
        plugin_output = prepare_upload_artifact(plugin_config_content,
                                                build_src_dir, schemas,
                                                plugin_manifest)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    # Write it to upload_artifact as json.
    try:
        generate_upload_artifact(upload_artifact, plugin_output)
    except exceptions.UserError as err:
        raise exceptions.BuildFailedError(err)

    logger.info('Successfully generated artifact file at %s.', upload_artifact)

    logger.warn('\nBUILD SUCCESSFUL.')