This is an automated email from the ASF dual-hosted git repository. lahirujayathilake pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/airavata-custos.git
commit e9c4e6587157e230fb595d5ed463d0d100daa9ee Author: lahiruj <[email protected]> AuthorDate: Fri Oct 10 14:59:29 2025 -0400 data models for ACCESS AMIE users and accounts --- .../custos/amie/model/ClusterAccountEntity.java | 124 +++++++++++++ .../apache/custos/amie/model/PersonDnsEntity.java | 87 ++++++++++ .../org/apache/custos/amie/model/PersonEntity.java | 192 +++++++++++++++++++++ .../custos/amie/repo/ClusterAccountRepository.java | 32 ++++ .../custos/amie/repo/PersonDnsRepository.java | 27 +++ .../apache/custos/amie/repo/PersonRepository.java | 38 ++++ .../db/migration/V1__initial_migration.sql | 59 +++++++ 7 files changed, 559 insertions(+) diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/model/ClusterAccountEntity.java b/amie-decoder/src/main/java/org/apache/custos/amie/model/ClusterAccountEntity.java new file mode 100644 index 000000000..fc45ddf0d --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/model/ClusterAccountEntity.java @@ -0,0 +1,124 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.Instant; + +/** + * Maps to the 'cluster_accounts' table. Stores a provisioned username on the cluster. + */ +@Entity +@Table(name = "cluster_accounts") +public class ClusterAccountEntity { + + @Id + @Column(name = "id") + private String id; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "person_id", nullable = false) + private PersonEntity person; + + @Column(name = "username", nullable = false, unique = true) + private String username; + + @Column(name = "is_active", nullable = false) + private boolean isActive = true; + + @CreationTimestamp + @Column(name = "created_at", nullable = false, updatable = false) + private Instant createdAt; + + @UpdateTimestamp + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public PersonEntity getPerson() { + return person; + } + + public void setPerson(PersonEntity person) { + this.person = person; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + + ClusterAccountEntity that = (ClusterAccountEntity) o; + return id.equals(that.id) && username.equals(that.username); + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + username.hashCode(); + return result; + } +} diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonDnsEntity.java b/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonDnsEntity.java new file mode 100644 index 000000000..911d61ba5 --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonDnsEntity.java @@ -0,0 +1,87 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; + +/** + * Maps to the 'person_dns' table. Stores a Distinguished Name (DN) for a person. + */ +@Entity +@Table(name = "person_dns", uniqueConstraints = {@UniqueConstraint(columnNames = {"person_id", "dn"})}) +public class PersonDnsEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "person_id", nullable = false) + private PersonEntity person; + + @Column(name = "dn", nullable = false, length = 512) + private String dn; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public PersonEntity getPerson() { + return person; + } + + public void setPerson(PersonEntity person) { + this.person = person; + } + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + + PersonDnsEntity that = (PersonDnsEntity) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonEntity.java b/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonEntity.java new file mode 100644 index 000000000..1603cfcf9 --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/model/PersonEntity.java @@ -0,0 +1,192 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +/** + * Maps to the 'persons' table. Stores a unique record for each person received from AMIE. + */ +@Entity +@Table(name = "persons") +public class PersonEntity { + + @Id + @Column(name = "id") + private String id; + + @Column(name = "access_global_id", nullable = false, unique = true) + private String accessGlobalId; + + @Column(name = "first_name", nullable = false) + private String firstName; + + @Column(name = "last_name", nullable = false) + private String lastName; + + @Column(name = "email", nullable = false) + private String email; + + @Column(name = "organization") + private String organization; + + @Column(name = "org_code") + private String orgCode; + + @Column(name = "nsf_status_code", length = 32) + private String nsfStatusCode; + + @CreationTimestamp + @Column(name = "created_at", nullable = false, updatable = false) + private Instant createdAt; + + @UpdateTimestamp + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + + @OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<PersonDnsEntity> dnsEntries = new ArrayList<>(); + + @OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<ClusterAccountEntity> clusterAccounts = new ArrayList<>(); + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAccessGlobalId() { + return accessGlobalId; + } + + public void setAccessGlobalId(String accessGlobalId) { + this.accessGlobalId = accessGlobalId; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getOrganization() { + return organization; + } + + public void setOrganization(String organization) { + this.organization = organization; + } + + public String getOrgCode() { + return orgCode; + } + + public void setOrgCode(String orgCode) { + this.orgCode = orgCode; + } + + public String getNsfStatusCode() { + return nsfStatusCode; + } + + public void setNsfStatusCode(String nsfStatusCode) { + this.nsfStatusCode = nsfStatusCode; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public List<PersonDnsEntity> getDnsEntries() { + return dnsEntries; + } + + public void setDnsEntries(List<PersonDnsEntity> dnsEntries) { + this.dnsEntries = dnsEntries; + } + + public List<ClusterAccountEntity> getClusterAccounts() { + return clusterAccounts; + } + + public void setClusterAccounts(List<ClusterAccountEntity> clusterAccounts) { + this.clusterAccounts = clusterAccounts; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + + PersonEntity that = (PersonEntity) o; + return id.equals(that.id) && accessGlobalId.equals(that.accessGlobalId); + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + accessGlobalId.hashCode(); + return result; + } +} + diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/repo/ClusterAccountRepository.java b/amie-decoder/src/main/java/org/apache/custos/amie/repo/ClusterAccountRepository.java new file mode 100644 index 000000000..05b8b2aca --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/repo/ClusterAccountRepository.java @@ -0,0 +1,32 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.repo; + +import org.apache.custos.amie.model.ClusterAccountEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface ClusterAccountRepository extends JpaRepository<ClusterAccountEntity, String> { + + Optional<ClusterAccountEntity> findByUsername(String username); + +} diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonDnsRepository.java b/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonDnsRepository.java new file mode 100644 index 000000000..5773bc306 --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonDnsRepository.java @@ -0,0 +1,27 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.repo; + +import org.apache.custos.amie.model.PersonDnsEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PersonDnsRepository extends JpaRepository<PersonDnsEntity, Long> { +} diff --git a/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonRepository.java b/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonRepository.java new file mode 100644 index 000000000..1f8254162 --- /dev/null +++ b/amie-decoder/src/main/java/org/apache/custos/amie/repo/PersonRepository.java @@ -0,0 +1,38 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.custos.amie.repo; + +import org.apache.custos.amie.model.PersonEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface PersonRepository extends JpaRepository<PersonEntity, String> { + + /** + * Finds a person by their unique AMIE Global ID. + * + * @param accessGlobalId The UserGlobalID from an AMIE packet. + * @return An Optional containing the PersonEntity if found. + */ + Optional<PersonEntity> findByAccessGlobalId(String accessGlobalId); + +} diff --git a/amie-decoder/src/main/resources/db/migration/V1__initial_migration.sql b/amie-decoder/src/main/resources/db/migration/V1__initial_migration.sql index 37ba745d6..9929d3236 100644 --- a/amie-decoder/src/main/resources/db/migration/V1__initial_migration.sql +++ b/amie-decoder/src/main/resources/db/migration/V1__initial_migration.sql @@ -7,6 +7,63 @@ SET NAMES utf8mb4; SET time_zone = '+00:00'; +-- ----------------------------- +-- TABLE: persons +-- Stores a unique record for each person received from AMIE. +-- ----------------------------- +CREATE TABLE persons +( + id VARCHAR(255) NOT NULL, -- Local user ID - UserPersonID + access_global_id VARCHAR(255) NOT NULL, -- UserGlobalID from AMIE + first_name VARCHAR(255) NOT NULL, + last_name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + organization VARCHAR(255) NULL, + org_code VARCHAR(255) NULL, + nsf_status_code VARCHAR(32) NULL, + created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + + PRIMARY KEY (id), + UNIQUE KEY uq_persons_amie_global_id (access_global_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +-- ----------------------------- +-- TABLE: person_dns +-- Stores the list of Distinguished Names (DNs) for a person. +-- ----------------------------- +CREATE TABLE person_dns +( + id BIGINT NOT NULL AUTO_INCREMENT, + person_id VARCHAR(255) NOT NULL, + dn VARCHAR(512) NOT NULL, + + PRIMARY KEY (id), + CONSTRAINT fk_dns_person FOREIGN KEY (person_id) REFERENCES persons (id) ON DELETE CASCADE, + UNIQUE KEY uq_person_dn (person_id, dn) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +-- ----------------------------- +-- TABLE: cluster_accounts +-- Stores the actual provisioned usernames on the cluster. +-- ----------------------------- +CREATE TABLE cluster_accounts +( + id VARCHAR(255) NOT NULL, + person_id VARCHAR(255) NOT NULL, + username VARCHAR(255) NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + + PRIMARY KEY (id), + UNIQUE KEY uq_accounts_username (username), + CONSTRAINT fk_accounts_person FOREIGN KEY (person_id) REFERENCES persons (id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + -- ----------------------------- -- TABLE: packets -- Stores each unique AMIE packet received from the polling endpoint @@ -30,6 +87,7 @@ CREATE TABLE packets KEY idx_packets_received_at (received_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + -- ----------------------------- -- TABLE: processing_events -- Individual processing steps for a given packet @@ -56,6 +114,7 @@ CREATE TABLE processing_events KEY idx_events_type (type) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + -- ----------------------------- -- TABLE: processing_errors -- Processing error logs
