<commit_before>package com.hazelcast.simulator.provisioner;

import com.hazelcast.simulator.agent.remoting.AgentRemoteService;
import com.hazelcast.simulator.agent.workerjvm.WorkerJvmManager;
import com.hazelcast.simulator.common.SimulatorProperties;
import com.hazelcast.simulator.utils.CommandLineExitException;
import org.apache.log4j.Logger;
import org.jclouds.aws.ec2.AWSEC2Api;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilderSpec;
import org.jclouds.ec2.domain.SecurityGroup;
import org.jclouds.ec2.features.SecurityGroupApi;
import org.jclouds.net.domain.IpProtocol;
import org.jclouds.scriptbuilder.statements.login.AdminAccess;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.hazelcast.simulator.utils.CloudProviderUtils.isEC2;

class TemplateBuilder {

    private static final int SSH_PORT = 22;
    private static final int HAZELCAST_PORT_RANGE_START = 5701;
    private static final int HAZELCAST_PORT_RANGE_END = 5751;

    private static final Logger LOGGER = Logger.getLogger(Provisioner.class);

    private final ComputeService compute;
    private final SimulatorProperties props;
    private String securityGroup;
    private TemplateBuilderSpec spec;

    TemplateBuilder(ComputeService compute, SimulatorProperties properties) {
        this.compute = compute;
        this.props = properties;
    }

    Template build() {
        securityGroup = props.get("SECURITY_GROUP", "simulator");

        String machineSpec = props.get("MACHINE_SPEC", "");
        spec = TemplateBuilderSpec.parse(machineSpec);
        LOGGER.info("Machine spec: " + machineSpec);

        Template template = buildTemplate();
        LOGGER.info("Created template");

        String user = props.get("USER", "simulator");
        AdminAccess adminAccess = AdminAccess.builder().adminUsername(user).build();
        LOGGER.info("Login name to the remote machines: " + user);

        template.getOptions()
                .inboundPorts(inboundPorts())
                .runScript(adminAccess);

        String subnetId = props.get("SUBNET_ID", "default");
        if (subnetId.equals("default") || subnetId.isEmpty()) {
            initSecurityGroup();
            template.getOptions().securityGroups(securityGroup);
        } else {
            if (!isEC2(props.get("CLOUD_PROVIDER"))) {
                throw new IllegalStateException("SUBNET_ID can be used only when EC2 is configured as a cloud provider.");
            }
            LOGGER.info("Using VPC, Subnet ID = " + subnetId);
            template.getOptions()
                    .as(AWSEC2TemplateOptions.class)
                    .subnetId(subnetId);
        }
        return template;
    }

    private Template buildTemplate() {
        try {
            return compute.templateBuilder().from(spec).build();
        } catch (IllegalArgumentException e) {
            throw new CommandLineExitException(e.getMessage());
        }
    }

    private int[] inboundPorts() {
        List<Integer> ports = new ArrayList<Integer>();
        ports.add(SSH_PORT);
        ports.add(AgentRemoteService.PORT);
        ports.add(WorkerJvmManager.PORT);
        for (int port = HAZELCAST_PORT_RANGE_START; port < HAZELCAST_PORT_RANGE_END; port++) {
            ports.add(port);
        }

        int[] result = new int[ports.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = ports.get(i);
        }
        return result;
    }

    private void initSecurityGroup() {
        if (!isEC2(props.get("CLOUD_PROVIDER"))) {
            return;
        }

        // in case of AWS, we are going to create the security group, if it doesn't exist
        AWSEC2Api ec2Api = compute.getContext().unwrapApi(AWSEC2Api.class);
        SecurityGroupApi securityGroupApi = ec2Api.getSecurityGroupApi().get();
        String region = spec.getLocationId();
        if (region == null) {
            region = "us-east-1";
        }

        Set<SecurityGroup> securityGroups = securityGroupApi.describeSecurityGroupsInRegion(region, securityGroup);
        if (!securityGroups.isEmpty()) {
            LOGGER.info("Security group: '" + securityGroup + "' is found in region '" + region + "'");
            return;
        }

        LOGGER.info("Security group: '" + securityGroup + "' is not found in region '" + region + "', creating it on the fly");

        securityGroupApi.createSecurityGroupInRegion(region, securityGroup, securityGroup);

        // this duplication of ports is ugly since we already do it in 'inboundPorts method'
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                SSH_PORT, SSH_PORT, "0.0.0.0/0");
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                AgentRemoteService.PORT, AgentRemoteService.PORT, "0.0.0.0/0");
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                WorkerJvmManager.PORT, WorkerJvmManager.PORT, "0.0.0.0/0");
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                HAZELCAST_PORT_RANGE_START, HAZELCAST_PORT_RANGE_END, "0.0.0.0/0");<commit_msg>Fixed duplicate literals issue in TemplateBuilder.<commit_after>package com.hazelcast.simulator.provisioner;

import com.hazelcast.simulator.agent.remoting.AgentRemoteService;
import com.hazelcast.simulator.agent.workerjvm.WorkerJvmManager;
import com.hazelcast.simulator.common.SimulatorProperties;
import com.hazelcast.simulator.utils.CommandLineExitException;
import org.apache.log4j.Logger;
import org.jclouds.aws.ec2.AWSEC2Api;
import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilderSpec;
import org.jclouds.ec2.domain.SecurityGroup;
import org.jclouds.ec2.features.SecurityGroupApi;
import org.jclouds.net.domain.IpProtocol;
import org.jclouds.scriptbuilder.statements.login.AdminAccess;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.hazelcast.simulator.utils.CloudProviderUtils.isEC2;

class TemplateBuilder {

    private static final int SSH_PORT = 22;
    private static final int HAZELCAST_PORT_RANGE_START = 5701;
    private static final int HAZELCAST_PORT_RANGE_END = 5751;

    private static final Logger LOGGER = Logger.getLogger(Provisioner.class);
    public static final String CIDR_RANGE = "0.0.0.0/0";

    private final ComputeService compute;
    private final SimulatorProperties props;
    private String securityGroup;
    private TemplateBuilderSpec spec;

    TemplateBuilder(ComputeService compute, SimulatorProperties properties) {
        this.compute = compute;
        this.props = properties;
    }

    Template build() {
        securityGroup = props.get("SECURITY_GROUP", "simulator");

        String machineSpec = props.get("MACHINE_SPEC", "");
        spec = TemplateBuilderSpec.parse(machineSpec);
        LOGGER.info("Machine spec: " + machineSpec);

        Template template = buildTemplate();
        LOGGER.info("Created template");

        String user = props.get("USER", "simulator");
        AdminAccess adminAccess = AdminAccess.builder().adminUsername(user).build();
        LOGGER.info("Login name to the remote machines: " + user);

        template.getOptions()
                .inboundPorts(inboundPorts())
                .runScript(adminAccess);

        String subnetId = props.get("SUBNET_ID", "default");
        if (subnetId.equals("default") || subnetId.isEmpty()) {
            initSecurityGroup();
            template.getOptions().securityGroups(securityGroup);
        } else {
            if (!isEC2(props.get("CLOUD_PROVIDER"))) {
                throw new IllegalStateException("SUBNET_ID can be used only when EC2 is configured as a cloud provider.");
            }
            LOGGER.info("Using VPC, Subnet ID = " + subnetId);
            template.getOptions()
                    .as(AWSEC2TemplateOptions.class)
                    .subnetId(subnetId);
        }
        return template;
    }

    private Template buildTemplate() {
        try {
            return compute.templateBuilder().from(spec).build();
        } catch (IllegalArgumentException e) {
            throw new CommandLineExitException(e.getMessage());
        }
    }

    private int[] inboundPorts() {
        List<Integer> ports = new ArrayList<Integer>();
        ports.add(SSH_PORT);
        ports.add(AgentRemoteService.PORT);
        ports.add(WorkerJvmManager.PORT);
        for (int port = HAZELCAST_PORT_RANGE_START; port < HAZELCAST_PORT_RANGE_END; port++) {
            ports.add(port);
        }

        int[] result = new int[ports.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = ports.get(i);
        }
        return result;
    }

    private void initSecurityGroup() {
        if (!isEC2(props.get("CLOUD_PROVIDER"))) {
            return;
        }

        // in case of AWS, we are going to create the security group, if it doesn't exist
        AWSEC2Api ec2Api = compute.getContext().unwrapApi(AWSEC2Api.class);
        SecurityGroupApi securityGroupApi = ec2Api.getSecurityGroupApi().get();
        String region = spec.getLocationId();
        if (region == null) {
            region = "us-east-1";
        }

        Set<SecurityGroup> securityGroups = securityGroupApi.describeSecurityGroupsInRegion(region, securityGroup);
        if (!securityGroups.isEmpty()) {
            LOGGER.info("Security group: '" + securityGroup + "' is found in region '" + region + "'");
            return;
        }

        LOGGER.info("Security group: '" + securityGroup + "' is not found in region '" + region + "', creating it on the fly");

        securityGroupApi.createSecurityGroupInRegion(region, securityGroup, securityGroup);

        // this duplication of ports is ugly since we already do it in 'inboundPorts method'
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                SSH_PORT, SSH_PORT, CIDR_RANGE);
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                AgentRemoteService.PORT, AgentRemoteService.PORT, CIDR_RANGE);
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                WorkerJvmManager.PORT, WorkerJvmManager.PORT, CIDR_RANGE);
        securityGroupApi.authorizeSecurityGroupIngressInRegion(region, securityGroup, IpProtocol.TCP,
                HAZELCAST_PORT_RANGE_START, HAZELCAST_PORT_RANGE_END, CIDR_RANGE);
{'fraction_non_alphanumeric': 0.10300311298297016, 'fraction_numerical': 0.007416224134773851, 'mean_word_length': 3.0455555555555556, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 5, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5834984', 'n_tokens_mistral': 3139, 'n_tokens_neox': 3085, 'n_words': 630}