This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch airavata-aws
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/airavata-aws by this push:
     new 0a09a41e26 Implement AWS task factory, EC2 instance creation workflow, 
and migration script
0a09a41e26 is described below

commit 0a09a41e2614d3500baa9c327ea85ee8dccc1eb2
Author: lahiruj <[email protected]>
AuthorDate: Thu Jun 26 19:16:47 2025 -0400

    Implement AWS task factory, EC2 instance creation workflow, and migration 
script
---
 modules/airavata-helix/helix-spectator/pom.xml     |   5 +
 .../airavata/helix/impl/task/AWSTaskFactory.java   |  69 ++++++++
 .../airavata/helix/impl/task/SlurmTaskFactory.java |  18 +--
 .../airavata/helix/impl/task/TaskFactory.java      |   1 +
 .../impl/task/aws/AWSProcessContextManager.java    | 116 ++++++++++++++
 .../helix/impl/task/aws/CreateEC2InstanceTask.java | 174 +++++++++++++++++++++
 .../init/06-cloud-execution-support-migration.sql  |  18 ++-
 .../AWSGroupComputeResourcePrefEntity.java         |  73 +++++++++
 .../appcatalog/GrpComputePrefRepository.java       |  15 ++
 .../src/main/resources/META-INF/persistence.xml    |   1 +
 .../group_resource_profile_model.thrift            |  11 ++
 11 files changed, 490 insertions(+), 11 deletions(-)

diff --git a/modules/airavata-helix/helix-spectator/pom.xml 
b/modules/airavata-helix/helix-spectator/pom.xml
index bc4a092282..d6e4b060aa 100644
--- a/modules/airavata-helix/helix-spectator/pom.xml
+++ b/modules/airavata-helix/helix-spectator/pom.xml
@@ -85,6 +85,11 @@ under the License.
             <artifactId>job-monitor-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>ec2</artifactId>
+            <version>2.31.70</version>
+        </dependency>
         <dependency>
             <groupId>com.github.docker-java</groupId>
             <artifactId>docker-java</artifactId>
diff --git 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
new file mode 100644
index 0000000000..a121d50e5a
--- /dev/null
+++ 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.airavata.helix.impl.task;
+
+import org.apache.airavata.helix.impl.task.aws.CreateEC2InstanceTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AWSTaskFactory implements HelixTaskFactory {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AWSTaskFactory.class);
+
+    @Override
+    public AiravataTask createEnvSetupTask(String processId) {
+        LOGGER.info("Creating AWS CreateEc2InstanceTask for process {}...", 
processId);
+        return new CreateEC2InstanceTask();
+    }
+
+    @Override
+    public AiravataTask createInputDataStagingTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createJobSubmissionTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createOutputDataStagingTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createArchiveTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createJobVerificationTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createCompletingTask(String processId) {
+        return null;
+    }
+
+    @Override
+    public AiravataTask createParsingTriggeringTask(String processId) {
+        return null;
+    }
+}
diff --git 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/SlurmTaskFactory.java
 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/SlurmTaskFactory.java
index b13a4a276c..8726b197a3 100644
--- 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/SlurmTaskFactory.java
+++ 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/SlurmTaskFactory.java
@@ -31,53 +31,53 @@ import org.slf4j.LoggerFactory;
 
 public class SlurmTaskFactory implements HelixTaskFactory {
 
-    private static final Logger logger = 
LoggerFactory.getLogger(SlurmTaskFactory.class);
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(SlurmTaskFactory.class);
 
     @Override
     public AiravataTask createEnvSetupTask(String processId) {
-        logger.info("Creating Slurm EnvSetupTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm EnvSetupTask for process {}...", 
processId);
         return new EnvSetupTask();
     }
 
     @Override
     public AiravataTask createInputDataStagingTask(String processId) {
-        logger.info("Creating Slurm InputDataStagingTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm InputDataStagingTask for process {}...", 
processId);
         return new InputDataStagingTask();
     }
 
     @Override
     public AiravataTask createJobSubmissionTask(String processId) {
-        logger.info("Creating Slurm DefaultJobSubmissionTask for process 
{}...", processId);
+        LOGGER.info("Creating Slurm DefaultJobSubmissionTask for process 
{}...", processId);
         return new DefaultJobSubmissionTask();
     }
 
     @Override
     public AiravataTask createOutputDataStagingTask(String processId) {
-        logger.info("Creating Slurm OutputDataStagingTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm OutputDataStagingTask for process {}...", 
processId);
         return new OutputDataStagingTask();
     }
 
     @Override
     public AiravataTask createArchiveTask(String processId) {
-        logger.info("Creating Slurm ArchiveTask for process {}...", processId);
+        LOGGER.info("Creating Slurm ArchiveTask for process {}...", processId);
         return new ArchiveTask();
     }
 
     @Override
     public AiravataTask createJobVerificationTask(String processId) {
-        logger.info("Creating Slurm JobVerificationTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm JobVerificationTask for process {}...", 
processId);
         return new JobVerificationTask();
     }
 
     @Override
     public AiravataTask createCompletingTask(String processId) {
-        logger.info("Creating Slurm CompletingTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm CompletingTask for process {}...", 
processId);
         return new CompletingTask();
     }
 
     @Override
     public AiravataTask createParsingTriggeringTask(String processId) {
-        logger.info("Creating Slurm ParsingTriggeringTask for process {}...", 
processId);
+        LOGGER.info("Creating Slurm ParsingTriggeringTask for process {}...", 
processId);
         return new ParsingTriggeringTask();
     }
 }
diff --git 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskFactory.java
 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskFactory.java
index 1cd0ca6549..c581d79431 100644
--- 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskFactory.java
+++ 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/TaskFactory.java
@@ -29,6 +29,7 @@ public class TaskFactory {
 
     static {
         FACTORIES.put(ResourceType.SLURM, new SlurmTaskFactory());
+        FACTORIES.put(ResourceType.AWS,   new AWSTaskFactory());
     }
 
     public static HelixTaskFactory getFactory(ResourceType type) {
diff --git 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSProcessContextManager.java
 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSProcessContextManager.java
new file mode 100644
index 0000000000..66c0bf3578
--- /dev/null
+++ 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSProcessContextManager.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.airavata.helix.impl.task.aws;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.airavata.agents.api.AgentException;
+import org.apache.airavata.agents.api.AgentUtils;
+import org.apache.airavata.helix.impl.task.TaskContext;
+import org.apache.airavata.model.process.ProcessModel;
+import org.apache.airavata.registry.api.RegistryService;
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manage AWS context
+ */
+public class AWSProcessContextManager {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AWSProcessContextManager.class);
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private static final String AWS_INSTANCE_ID_KEY = "AWS_INSTANCE_ID";
+    private static final String AWS_SECURITY_GROUP_ID_KEY = 
"AWS_SECURITY_GROUP_ID";
+    private static final String AWS_KEY_PAIR_NAME_KEY = "AWS_KEY_PAIR_NAME";
+    private static final String AWS_SSH_CREDENTIAL_TOKEN = 
"AWS_SSH_CREDENTIAL_TOKEN";
+
+
+    private final RegistryService.Client registryClient;
+    private final TaskContext taskContext;
+    private final String processId;
+
+    public AWSProcessContextManager(TaskContext taskContext) {
+        try {
+            this.registryClient = AgentUtils.getRegistryServiceClient();
+            this.taskContext = taskContext;
+            this.processId = taskContext.getProcessId();
+            LOGGER.info("Initialized AWSProcessContextManager for process {}", 
processId);
+
+        } catch (AgentException e) {
+            LOGGER.error("Failed to initialize AWSProcessContextManager", e);
+            throw new RuntimeException("Failed to initialize 
AWSProcessContextManager", e);
+        }
+    }
+
+    public String getInstanceId() throws IOException {
+        return getContextMap().get(AWS_INSTANCE_ID_KEY);
+    }
+
+    public void saveInstanceId(String instanceId) throws TException, 
IOException {
+        updateContext(AWS_INSTANCE_ID_KEY, instanceId);
+    }
+
+    public String getSecurityGroupId() throws IOException {
+        return getContextMap().get(AWS_SECURITY_GROUP_ID_KEY);
+    }
+
+    public void saveSecurityGroupId(String securityGroupId) throws TException, 
IOException {
+        updateContext(AWS_SECURITY_GROUP_ID_KEY, securityGroupId);
+    }
+
+    public String getKeyPairName() throws IOException {
+        return getContextMap().get(AWS_KEY_PAIR_NAME_KEY);
+    }
+
+    public void saveKeyPairName(String keyPairName) throws TException, 
IOException {
+        updateContext(AWS_KEY_PAIR_NAME_KEY, keyPairName);
+    }
+
+    public String getSSHCredentialToken() throws IOException {
+        return getContextMap().get(AWS_SSH_CREDENTIAL_TOKEN);
+    }
+
+    public void saveSSHCredentialToken(String credentialToken) throws 
TException, IOException {
+        updateContext(AWS_SSH_CREDENTIAL_TOKEN, credentialToken);
+    }
+
+    private Map<String, String> getContextMap() throws IOException {
+        String jsonContext = taskContext.getProcessModel().getProcessDetail();
+        if (jsonContext == null || jsonContext.isEmpty()) {
+            return new HashMap<>();
+        }
+        return MAPPER.readValue(jsonContext, new TypeReference<>() {
+        });
+    }
+
+    private void updateContext(String key, String value) throws TException, 
IOException {
+        Map<String, String> contextMap = getContextMap();
+        contextMap.put(key, value);
+        ProcessModel processModel = taskContext.getProcessModel();
+        processModel.setProcessDetail(MAPPER.writeValueAsString(contextMap));
+        registryClient.updateProcess(processModel, processId);
+        LOGGER.info("Updated process detail for process {} with key '{}'", 
processId, key);
+    }
+}
diff --git 
a/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/CreateEC2InstanceTask.java
 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/CreateEC2InstanceTask.java
new file mode 100644
index 0000000000..303e7051e5
--- /dev/null
+++ 
b/modules/airavata-helix/helix-spectator/src/main/java/org/apache/airavata/helix/impl/task/aws/CreateEC2InstanceTask.java
@@ -0,0 +1,174 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.airavata.helix.impl.task.aws;
+
+import org.apache.airavata.agents.api.AgentUtils;
+import org.apache.airavata.helix.impl.task.AiravataTask;
+import org.apache.airavata.helix.impl.task.TaskContext;
+import org.apache.airavata.helix.task.api.TaskHelper;
+import 
org.apache.airavata.model.appcatalog.groupresourceprofile.AwsComputeResourcePreference;
+import org.apache.airavata.model.credential.store.PasswordCredential;
+import org.apache.airavata.model.credential.store.SSHCredential;
+import org.apache.helix.task.TaskResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.ec2.Ec2Client;
+import software.amazon.awssdk.services.ec2.model.CreateKeyPairResponse;
+import software.amazon.awssdk.services.ec2.model.CreateSecurityGroupResponse;
+import software.amazon.awssdk.services.ec2.model.InstanceType;
+import software.amazon.awssdk.services.ec2.model.RunInstancesRequest;
+import software.amazon.awssdk.services.ec2.model.RunInstancesResponse;
+
+import java.util.UUID;
+
+/**
+ * Create all required AWS resources (SecurityGroup, KeyPair) and launches an 
EC2 instance
+ */
+public class CreateEC2InstanceTask extends AiravataTask {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(CreateEC2InstanceTask.class);
+
+    @Override
+    public TaskResult onRun(TaskHelper helper, TaskContext taskContext) {
+        LOGGER.info("Starting Create EC2 Instance Task for process {}", 
getProcessId());
+
+        AWSProcessContextManager awsContext = new 
AWSProcessContextManager(taskContext);
+        Ec2Client ec2Client = null;
+
+        try {
+            AwsComputeResourcePreference awsPrefs = 
taskContext.getGroupComputeResourcePreference().getSpecificPreferences().getAws();
+            String credentialToken = 
taskContext.getGroupComputeResourcePreference().getResourceSpecificCredentialStoreToken();
+
+            ec2Client = buildEc2Client(credentialToken, getGatewayId(), 
awsPrefs.getRegion());
+            LOGGER.info("Successfully built EC2 client for region {}", 
awsPrefs.getRegion());
+
+            String securityGroupId = createSecurityGroup(ec2Client);
+            awsContext.saveSecurityGroupId(securityGroupId);
+            LOGGER.info("Created and saved security group: {}", 
securityGroupId);
+
+            String keyPairName = "airavata-key-" + getProcessId();
+            CreateKeyPairResponse kpRes = ec2Client.createKeyPair(req -> 
req.keyName(keyPairName));
+            awsContext.saveKeyPairName(keyPairName);
+
+            String sshCredentialToken = saveSSHCredential(kpRes.keyMaterial());
+            awsContext.saveSSHCredentialToken(sshCredentialToken);
+            LOGGER.info("Created key pair {} and saved credential with token 
{}", keyPairName, sshCredentialToken);
+
+            RunInstancesRequest runRequest = RunInstancesRequest.builder()
+                    .imageId(awsPrefs.getPreferredAmiId())
+                    
.instanceType(InstanceType.fromValue(awsPrefs.getPreferredInstanceType()))
+                    .keyName(keyPairName)
+                    .securityGroupIds(securityGroupId)
+                    .minCount(1)
+                    .maxCount(1)
+                    .build();
+            RunInstancesResponse runResponse = 
ec2Client.runInstances(runRequest);
+
+            if (runResponse.instances() == null || 
runResponse.instances().isEmpty()) {
+                LOGGER.error("No instances were launched by AWS even after 
successful SDK call");
+                throw new Exception("No instances were launched by AWS even 
after successful SDK call");
+            }
+
+            String instanceId = runResponse.instances().get(0).instanceId();
+            awsContext.saveInstanceId(instanceId);
+            LOGGER.info("Successfully launched EC2 instance {}", instanceId);
+
+            return new TaskResult(TaskResult.Status.COMPLETED, "Launched EC2 
instance " + instanceId);
+
+        } catch (Exception e) {
+            // TODO catch for AMI issues, etc
+            LOGGER.error("Error creating EC2 instance for process {}", 
getProcessId(), e);
+            onCancel(taskContext);
+            return new TaskResult(TaskResult.Status.FATAL_FAILED, 
e.getMessage());
+
+        } finally {
+            if (ec2Client != null) {
+                ec2Client.close();
+            }
+        }
+    }
+
+    @Override
+    public void onCancel(TaskContext taskContext) {
+        LOGGER.warn("Cleaning up resources for failed CreateEC2InstanceTask, 
process: {}", getProcessId());
+        try {
+            AWSProcessContextManager awsContext = new 
AWSProcessContextManager(taskContext);
+            AwsComputeResourcePreference awsPrefs = 
taskContext.getGroupComputeResourcePreference().getSpecificPreferences().getAws();
+            String credentialToken = 
taskContext.getGroupComputeResourcePreference().getResourceSpecificCredentialStoreToken();
+
+            try (Ec2Client ec2Client = buildEc2Client(credentialToken, 
getGatewayId(), awsPrefs.getRegion())) {
+                String sgId = awsContext.getSecurityGroupId();
+                String keyName = awsContext.getKeyPairName();
+
+                if (sgId != null) {
+                    LOGGER.warn("Deleting security group: {}", sgId);
+                    ec2Client.deleteSecurityGroup(req -> req.groupId(sgId));
+                }
+                if (keyName != null) {
+                    LOGGER.warn("Deleting key pair: {}", keyName);
+                    ec2Client.deleteKeyPair(req -> req.keyName(keyName));
+                }
+
+                
AgentUtils.getCredentialClient().deleteSSHCredential(awsContext.getSSHCredentialToken(),
 getGatewayId());
+            }
+        } catch (Exception e) {
+            LOGGER.error("Failed to cleanup resources during onCancel. Manual 
intervention may be required.", e);
+        }
+    }
+
+    private Ec2Client buildEc2Client(String token, String gatewayId, String 
region) throws Exception {
+        PasswordCredential pwdCred = 
AgentUtils.getCredentialClient().getPasswordCredential(token, gatewayId);
+        AwsBasicCredentials awsCreds = 
AwsBasicCredentials.create(pwdCred.getLoginUserName(), pwdCred.getPassword()); 
// TODO support using AWS Credential
+        return Ec2Client.builder()
+                .region(Region.of(region))
+                
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
+                .build();
+    }
+
+    // Save the generated aws private key in Airavata Credential Store
+    private String saveSSHCredential(String privateKey) throws Exception {
+        SSHCredential credential = new SSHCredential();
+        credential.setGatewayId(getGatewayId());
+        credential.setToken(UUID.randomUUID().toString());
+        credential.setPrivateKey(privateKey);
+        credential.setUsername(getProcessModel().getUserName());
+
+        String savedToken = 
AgentUtils.getCredentialClient().addSSHCredential(credential);
+        LOGGER.info("Successfully saved temporary SSH credential with token 
{}", savedToken);
+
+        return savedToken;
+    }
+
+    private String createSecurityGroup(Ec2Client ec2) throws Exception {
+        String vpcId = ec2.describeVpcs(req -> req.filters(f -> 
f.name("is-default").values("true"))).vpcs().get(0).vpcId();
+        CreateSecurityGroupResponse sgRes = ec2.createSecurityGroup(req -> req
+                .groupName("airavata-sg-" + getProcessId())
+                .description("Airavata temporary security group for " + 
getProcessId())
+                .vpcId(vpcId));
+
+        ec2.authorizeSecurityGroupIngress(req -> req
+                .groupId(sgRes.groupId())
+                .ipPermissions(p -> 
p.ipProtocol("tcp").fromPort(22).toPort(22).ipRanges(r -> 
r.cidrIp("0.0.0.0/0")))); // TODO restrict the IP
+
+        return sgRes.groupId();
+    }
+}
diff --git 
a/modules/ide-integration/src/main/containers/database_scripts/init/06-cloud-execution-support-migration.sql
 
b/modules/ide-integration/src/main/containers/database_scripts/init/06-cloud-execution-support-migration.sql
index 4da86e8141..bc2e7c1cab 100644
--- 
a/modules/ide-integration/src/main/containers/database_scripts/init/06-cloud-execution-support-migration.sql
+++ 
b/modules/ide-integration/src/main/containers/database_scripts/init/06-cloud-execution-support-migration.sql
@@ -57,7 +57,6 @@ SELECT
     `SSH_ACCOUNT_PROVISIONER_ADDITIONAL_INFO`
 FROM `GROUP_COMPUTE_RESOURCE_PREFERENCE`;
 
-
 -- Drop the Slurm-specific columns from the base table
 ALTER TABLE `GROUP_COMPUTE_RESOURCE_PREFERENCE`
 DROP COLUMN `PREFERED_BATCH_QUEUE`,
@@ -69,4 +68,19 @@ DROP COLUMN `PREFERED_BATCH_QUEUE`,
   DROP COLUMN `RESERVATION_START_TIME`,
   DROP COLUMN `RESERVATION_END_TIME`,
   DROP COLUMN `SSH_ACCOUNT_PROVISIONER`,
-  DROP COLUMN `SSH_ACCOUNT_PROVISIONER_ADDITIONAL_INFO`;
\ No newline at end of file
+  DROP COLUMN `SSH_ACCOUNT_PROVISIONER_ADDITIONAL_INFO`;
+
+-- Create the AWS-specific group compute preference table
+CREATE TABLE `AWS_GROUP_COMPUTE_RESOURCE_PREFERENCE`
+(
+    `RESOURCE_ID`                 VARCHAR(255) NOT NULL,
+    `GROUP_RESOURCE_PROFILE_ID`   VARCHAR(255) NOT NULL,
+    `AWS_REGION`                  VARCHAR(255) NOT NULL,
+    `PREFERRED_AMI_ID`            VARCHAR(255) NOT NULL,
+    `PREFERRED_INSTANCE_TYPE`     VARCHAR(255) NOT NULL,
+
+    PRIMARY KEY (`RESOURCE_ID`, `GROUP_RESOURCE_PROFILE_ID`),
+    CONSTRAINT `FK_AWS_PREF_TO_BASE` FOREIGN KEY (`RESOURCE_ID`, 
`GROUP_RESOURCE_PROFILE_ID`)
+        REFERENCES `GROUP_COMPUTE_RESOURCE_PREFERENCE` (`RESOURCE_ID`, 
`GROUP_RESOURCE_PROFILE_ID`)
+        ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
\ No newline at end of file
diff --git 
a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/entities/appcatalog/AWSGroupComputeResourcePrefEntity.java
 
b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/entities/appcatalog/AWSGroupComputeResourcePrefEntity.java
new file mode 100644
index 0000000000..b7675f7518
--- /dev/null
+++ 
b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/entities/appcatalog/AWSGroupComputeResourcePrefEntity.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.airavata.registry.core.entities.appcatalog;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.PrimaryKeyJoinColumn;
+import jakarta.persistence.PrimaryKeyJoinColumns;
+import jakarta.persistence.Table;
+
+/**
+ * The persistent class for the aws_group_compute_resource_preference database 
table.
+ */
+@Entity
+@Table(name = "AWS_GROUP_COMPUTE_RESOURCE_PREFERENCE")
+@PrimaryKeyJoinColumns({
+        @PrimaryKeyJoinColumn(name = "RESOURCE_ID", referencedColumnName = 
"RESOURCE_ID"),
+        @PrimaryKeyJoinColumn(name = "GROUP_RESOURCE_PROFILE_ID", 
referencedColumnName = "GROUP_RESOURCE_PROFILE_ID")
+})
+public class AWSGroupComputeResourcePrefEntity extends 
GroupComputeResourcePrefEntity {
+
+    @Column(name = "AWS_REGION", nullable = false)
+    private String region;
+
+    @Column(name = "PREFERRED_AMI_ID", nullable = false)
+    private String preferredAmiId;
+
+    @Column(name = "PREFERRED_INSTANCE_TYPE", nullable = false)
+    private String preferredInstanceType;
+
+    public AWSGroupComputeResourcePrefEntity() {
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getPreferredAmiId() {
+        return preferredAmiId;
+    }
+
+    public void setPreferredAmiId(String preferredAmiId) {
+        this.preferredAmiId = preferredAmiId;
+    }
+
+    public String getPreferredInstanceType() {
+        return preferredInstanceType;
+    }
+
+    public void setPreferredInstanceType(String preferredInstanceType) {
+        this.preferredInstanceType = preferredInstanceType;
+    }
+}
diff --git 
a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/repositories/appcatalog/GrpComputePrefRepository.java
 
b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/repositories/appcatalog/GrpComputePrefRepository.java
index 41ec472ed2..7a6846106c 100644
--- 
a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/repositories/appcatalog/GrpComputePrefRepository.java
+++ 
b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/repositories/appcatalog/GrpComputePrefRepository.java
@@ -18,10 +18,12 @@
  */
 package org.apache.airavata.registry.core.repositories.appcatalog;
 
+import 
org.apache.airavata.model.appcatalog.groupresourceprofile.AwsComputeResourcePreference;
 import 
org.apache.airavata.model.appcatalog.groupresourceprofile.EnvironmentSpecificPreferences;
 import 
org.apache.airavata.model.appcatalog.groupresourceprofile.GroupComputeResourcePreference;
 import org.apache.airavata.model.appcatalog.groupresourceprofile.ResourceType;
 import 
org.apache.airavata.model.appcatalog.groupresourceprofile.SlurmComputeResourcePreference;
+import 
org.apache.airavata.registry.core.entities.appcatalog.AWSGroupComputeResourcePrefEntity;
 import 
org.apache.airavata.registry.core.entities.appcatalog.GroupComputeResourcePrefEntity;
 import 
org.apache.airavata.registry.core.entities.appcatalog.GroupComputeResourcePrefPK;
 import 
org.apache.airavata.registry.core.entities.appcatalog.SlurmGroupComputeResourcePrefEntity;
@@ -65,6 +67,19 @@ public class GrpComputePrefRepository
             EnvironmentSpecificPreferences esp = new 
EnvironmentSpecificPreferences();
             esp.setSlurm(scrp);
             pref.setSpecificPreferences(esp);
+
+        } else if (ent instanceof AWSGroupComputeResourcePrefEntity aws) {
+            pref.setResourceType(ResourceType.AWS);
+
+            AwsComputeResourcePreference awsPref = new 
AwsComputeResourcePreference();
+            awsPref.setRegion(aws.getRegion());
+            awsPref.setPreferredAmiId(aws.getPreferredAmiId());
+            awsPref.setPreferredInstanceType(aws.getPreferredInstanceType());
+
+            EnvironmentSpecificPreferences esp = new 
EnvironmentSpecificPreferences();
+            esp.setAws(awsPref);
+            pref.setSpecificPreferences(esp);
+            return pref;
         }
 
         return pref;
diff --git 
a/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml 
b/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
index bb5b7af886..53903e91f8 100644
--- a/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
+++ b/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
@@ -67,6 +67,7 @@
         
<class>org.apache.airavata.registry.core.entities.appcatalog.ComputeResourcePolicyEntity</class>
         
<class>org.apache.airavata.registry.core.entities.appcatalog.GroupComputeResourcePrefEntity</class>
         
<class>org.apache.airavata.registry.core.entities.appcatalog.SlurmGroupComputeResourcePrefEntity</class>
+        
<class>org.apache.airavata.registry.core.entities.appcatalog.AWSGroupComputeResourcePrefEntity</class>
         
<class>org.apache.airavata.registry.core.entities.appcatalog.GroupSSHAccountProvisionerConfig</class>
         
<class>org.apache.airavata.registry.core.entities.appcatalog.GroupResourceProfileEntity</class>
         
<class>org.apache.airavata.registry.core.entities.appcatalog.ModuleLoadCmdEntity</class>
diff --git 
a/thrift-interface-descriptions/data-models/group_resource_profile_model.thrift 
b/thrift-interface-descriptions/data-models/group_resource_profile_model.thrift
index 1f4f04a77e..357d3fbe61 100644
--- 
a/thrift-interface-descriptions/data-models/group_resource_profile_model.thrift
+++ 
b/thrift-interface-descriptions/data-models/group_resource_profile_model.thrift
@@ -44,6 +44,7 @@ struct ComputeResourceReservation {
 
 enum ResourceType {
   SLURM = 0,
+  AWS = 1,
 }
 
 struct SlurmComputeResourcePreference {
@@ -58,8 +59,18 @@ struct SlurmComputeResourcePreference {
     9: optional list<ComputeResourceReservation> reservations
 }
 
+struct AwsComputeResourcePreference {
+    1: optional string preferredAmiId,
+    2: optional string preferredInstanceType,
+    3: optional string region,
+    4: optional string securityGroupId,
+    5: optional string keyPairName,
+    6: optional i64    maxStartupTime,
+}
+
 union EnvironmentSpecificPreferences {
     1: SlurmComputeResourcePreference slurm,
+    2: AwsComputeResourcePreference aws,
 }
 
 struct GroupComputeResourcePreference {

Reply via email to