From 35e1b933133b6f880d7967de26b7a2266b401a23 Mon Sep 17 00:00:00 2001 From: Evangelos Chaniotakis Date: Tue, 26 Mar 2024 16:40:31 -0700 Subject: [PATCH] fix: [OS-292] fix database transaction error (#467) --- CHANGES.md | 6 ++ backend/config/application.properties | 12 +++- backend/config/logback.xml | 7 ++ backend/pom.xml | 62 +++++++++-------- .../main/java/net/es/oscars/app/Startup.java | 31 ++++----- .../oscars/app/otel/RestTemplateConfig.java | 38 +++++++++++ .../net/es/oscars/app/ser/JacksonConfig.java | 1 - .../java/net/es/oscars/resv/ent/Archived.java | 24 ++++++- .../net/es/oscars/resv/ent/CommandParam.java | 27 +++++++- .../net/es/oscars/resv/ent/Components.java | 27 +++++++- .../net/es/oscars/resv/ent/Connection.java | 27 +++++++- .../java/net/es/oscars/resv/ent/Design.java | 24 ++++++- .../java/net/es/oscars/resv/ent/EroHop.java | 24 ++++++- .../java/net/es/oscars/resv/ent/Event.java | 26 +++++++- .../java/net/es/oscars/resv/ent/EventLog.java | 24 ++++++- .../java/net/es/oscars/resv/ent/Held.java | 25 ++++++- .../java/net/es/oscars/resv/ent/Reserved.java | 22 ++++++- .../java/net/es/oscars/resv/ent/Schedule.java | 28 ++++++-- .../main/java/net/es/oscars/resv/ent/Tag.java | 26 ++++++-- .../net/es/oscars/resv/ent/TagCategory.java | 27 ++++++-- .../java/net/es/oscars/resv/ent/Vlan.java | 26 +++++++- .../net/es/oscars/resv/ent/VlanFixture.java | 25 ++++++- .../net/es/oscars/resv/ent/VlanJunction.java | 25 ++++++- .../java/net/es/oscars/resv/ent/VlanPipe.java | 26 +++++++- .../net/es/oscars/resv/svc/ConnService.java | 66 ++++++++++++++----- .../net/es/oscars/topo/pop/TopoPopulator.java | 15 +++-- .../es/oscars/web/rest/HoldController.java | 12 ++++ .../web/rest/NsoLiveStatusController.java | 21 ++++-- .../oscars/web/rest/SimpleApiController.java | 1 + deploy/devel/backend.dockerfile | 2 +- deploy/prod/backend.dockerfile | 2 +- 31 files changed, 584 insertions(+), 125 deletions(-) create mode 100644 backend/src/main/java/net/es/oscars/app/otel/RestTemplateConfig.java diff --git a/CHANGES.md b/CHANGES.md index 308680d8a..ce48e8e39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # OSCARS Release Notes +### 1.2.4 +> Mar 2024 +- further opentelemetry integration +- bug fixes for Hibernate commit errors + ### 1.2.3 +> Mar 2024 - OS-285: fix operational state bugs ### 1.2.2 diff --git a/backend/config/application.properties b/backend/config/application.properties index 66637bfbe..112d8c053 100644 --- a/backend/config/application.properties +++ b/backend/config/application.properties @@ -105,9 +105,15 @@ spring.security.oauth2.client.registration.keycloak.authorization-grant-type=aut spring.security.oauth2.client.registration.keycloak.scope=openid # for opentelemetry -otel.sdk.disabled=true -# otel.propagators=tracecontext,b3 -# otel.resource.attributes=environment=dev,xyz=foo +#otel.sdk.disabled=true // uncomment this to disable OTEL +otel.service.name=oscars-backend +otel.service.version=1.2 +otel.traces.exporter=otlp +otel.metrics.exporter=otlp +otel.logs.exporter=otlp +otel.exporter.otlp.endpoint=https://eapm2.gc1.dev.stardust.es.net:8200 +otel.exporter.otlp.headers=authorization: ApiKey +otel.resource.attributes=deployment.environment=development frontend.oauth-client-id=local-oscars-frontend diff --git a/backend/config/logback.xml b/backend/config/logback.xml index 16cfa74a4..14b80aae9 100644 --- a/backend/config/logback.xml +++ b/backend/config/logback.xml @@ -41,6 +41,9 @@ %msg + + + @@ -70,5 +73,9 @@ + + + diff --git a/backend/pom.xml b/backend/pom.xml index 4d1c2988c..2a145df7d 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -7,14 +7,14 @@ org.springframework.boot spring-boot-starter-parent - 3.1.10 + 3.2.4 net.es.oscars backend backend - 1.2.3 + 1.2.4 OSCARS backend @@ -23,10 +23,6 @@ 17 UTF-8 UTF-8 - 3.5.0 - - 1.18.30 - --tags @unit --strict @@ -40,6 +36,10 @@ nsi https://gitlab.es.net/api/v4/projects/828/packages/maven + + apache maven + https://repo.maven.apache.org/maven2/ + @@ -96,7 +96,7 @@ org.projectlombok lombok - ${lombok.version} + 1.18.32 provided @@ -116,32 +116,43 @@ io.opentelemetry.instrumentation opentelemetry-spring-boot-starter + + io.opentelemetry.instrumentation + opentelemetry-spring-web-3.1 + 2.2.0-alpha + + + io.opentelemetry.instrumentation + opentelemetry-jdbc + + + io.hypersistence hypersistence-utils-hibernate-62 - 3.5.0 + 3.6.0 com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.15.2 + 2.16.1 com.fasterxml.jackson.core jackson-core - 2.15.2 + 2.16.1 com.fasterxml.jackson.core jackson-databind - 2.15.2 + 2.16.1 com.fasterxml.jackson.core jackson-annotations - 2.15.2 + 2.16.1 @@ -166,7 +177,7 @@ org.eclipse.jetty jetty-xml - 11.0.16 + 12.0.7 @@ -225,22 +236,22 @@ org.apache.cxf cxf-spring-boot-starter-jaxws - 4.0.2 + 4.0.4 org.apache.cxf cxf-rt-features-logging - 4.0.2 + 4.0.4 org.jgrapht jgrapht-core - 1.5.1 + 1.5.2 org.apache.httpcomponents.client5 httpclient5 - 5.2.1 + 5.3 javax.servlet @@ -274,12 +285,12 @@ com.github.seancfoley ipaddress - 5.4.0 + 5.5.0 org.apache.commons commons-lang3 - 3.12.0 + 3.14.0 @@ -303,19 +314,19 @@ io.cucumber cucumber-java - 7.13.0 + 7.16.1 test io.cucumber cucumber-junit - 7.13.0 + 7.16.0 test io.cucumber cucumber-spring - 7.13.0 + 7.16.0 test @@ -335,11 +346,6 @@ jakarta.servlet-api 6.0.0 - - org.eclipse.jetty - jetty-server - 11.0.15 - @@ -351,7 +357,7 @@ org.apache.maven.plugins maven-dependency-plugin - ${maven-dependency-plugin.version} + 3.6.1 diff --git a/backend/src/main/java/net/es/oscars/app/Startup.java b/backend/src/main/java/net/es/oscars/app/Startup.java index b15884e35..c426f0225 100644 --- a/backend/src/main/java/net/es/oscars/app/Startup.java +++ b/backend/src/main/java/net/es/oscars/app/Startup.java @@ -1,10 +1,12 @@ package net.es.oscars.app; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.instrumentation.annotations.WithSpan; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.es.oscars.app.exc.StartupException; import net.es.oscars.app.props.StartupProperties; -import net.es.oscars.app.syslog.Syslogger; import net.es.oscars.sb.nso.resv.LegacyPopulator; import net.es.oscars.topo.beans.TopoException; import net.es.oscars.topo.pop.ConsistencyException; @@ -26,25 +28,16 @@ public class Startup { private final List components; private final StartupProperties startupProperties; - private final Syslogger syslogger; - private final TopoPopulator topoPopulator; - private final LegacyPopulator legacyPopulator; + @Setter @Getter private boolean inStartup = true; + @Setter @Getter private boolean inShutdown = false; - public void setInStartup(boolean inStartup) { - this.inStartup = inStartup; - } - - public void setInShutdown(boolean inShutdown) { - this.inShutdown = inShutdown; - } - @Bean public Executor taskExecutor() { @@ -53,27 +46,30 @@ public Executor taskExecutor() { @Autowired public Startup(StartupProperties startupProperties, - Syslogger syslogger, TopoPopulator topoPopulator, UIPopulator uiPopulator, LegacyPopulator legacyPopulator) { this.startupProperties = startupProperties; this.topoPopulator = topoPopulator; - this.syslogger = syslogger; this.legacyPopulator = legacyPopulator; components = new ArrayList<>(); components.add(uiPopulator); } + @WithSpan(value="startup") public void onStart() throws IOException, ConsistencyException, TopoException { System.out.println(startupProperties.getBanner()); + Span currentSpan = Span.current(); + + currentSpan.addEvent("starting up"); + currentSpan.setAttribute("isTestAttribute", true); + log.info("OSCARS starting up"); this.setInStartup(true); if (startupProperties.getExit()) { - log.info("In Shutdown"); + log.info("OSCARS shutting down"); this.setInStartup(false); this.setInShutdown(true); - syslogger.sendSyslog("OSCARS APPLICATION SHUTDOWN COMPLETED"); System.out.println("Exiting (startup.exit is true)"); System.exit(0); } @@ -89,9 +85,6 @@ public void onStart() throws IOException, ConsistencyException, TopoException { System.out.println("Exiting.."); System.exit(1); } - log.info("OSCARS startup successful."); - - syslogger.sendSyslog("OSCARS APPLICATION STARTUP COMPLETED"); this.setInStartup(false); diff --git a/backend/src/main/java/net/es/oscars/app/otel/RestTemplateConfig.java b/backend/src/main/java/net/es/oscars/app/otel/RestTemplateConfig.java new file mode 100644 index 000000000..6f023a5c6 --- /dev/null +++ b/backend/src/main/java/net/es/oscars/app/otel/RestTemplateConfig.java @@ -0,0 +1,38 @@ +package net.es.oscars.app.otel; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.spring.web.v3_1.SpringWebTelemetry; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.client.RestTemplateCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +@Slf4j +public class RestTemplateConfig { + final + OpenTelemetry openTelemetry; + + public RestTemplateConfig(OpenTelemetry openTelemetry) { + this.openTelemetry = openTelemetry; + } + + @Bean + public CustomRestTemplateCustomizer customRestTemplateCustomizer() { + return new CustomRestTemplateCustomizer(); + } + + public class CustomRestTemplateCustomizer implements RestTemplateCustomizer { + @Override + public void customize(RestTemplate restTemplate) { + log.info("adding otel to rest template"); + SpringWebTelemetry telemetry = SpringWebTelemetry.create(openTelemetry); + restTemplate.getInterceptors().add(telemetry.newInterceptor()); + + } + } + +} + + diff --git a/backend/src/main/java/net/es/oscars/app/ser/JacksonConfig.java b/backend/src/main/java/net/es/oscars/app/ser/JacksonConfig.java index b144aa104..c418eaf72 100644 --- a/backend/src/main/java/net/es/oscars/app/ser/JacksonConfig.java +++ b/backend/src/main/java/net/es/oscars/app/ser/JacksonConfig.java @@ -13,7 +13,6 @@ public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer addLombokIntrospection() { return jacksonObjectMapperBuilder -> { - log.info("customizing jackson"); jacksonObjectMapperBuilder.failOnUnknownProperties(true); jacksonObjectMapperBuilder.modules(new JavaTimeModule()); }; diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Archived.java b/backend/src/main/java/net/es/oscars/resv/ent/Archived.java index 731d35760..1a3b7ba0f 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Archived.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Archived.java @@ -3,11 +3,15 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString @Entity @Builder @AllArgsConstructor @@ -28,7 +32,7 @@ public Archived(@JsonProperty("connectionId") @NonNull String connectionId, private Long id; @NonNull - @Column(unique = true) + @Column private String connectionId; @NonNull @@ -39,5 +43,19 @@ public Archived(@JsonProperty("connectionId") @NonNull String connectionId, @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) private Schedule schedule; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Archived archived = (Archived) o; + return getId() != null && Objects.equals(getId(), archived.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/CommandParam.java b/backend/src/main/java/net/es/oscars/resv/ent/CommandParam.java index 2123a47fe..97edb5848 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/CommandParam.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/CommandParam.java @@ -3,13 +3,21 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.*; import net.es.oscars.resv.enums.CommandParamIntent; import net.es.oscars.topo.enums.CommandParamType; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Builder @NoArgsConstructor @AllArgsConstructor @@ -43,4 +51,19 @@ public class CommandParam { @NonNull private Integer resource; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + CommandParam that = (CommandParam) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Components.java b/backend/src/main/java/net/es/oscars/resv/ent/Components.java index 048d9770f..cef72ddf0 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Components.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Components.java @@ -4,12 +4,17 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; import java.util.List; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -32,14 +37,32 @@ public Components(@JsonProperty("junctions") @NonNull List junctio @NonNull @OneToMany(cascade = CascadeType.ALL) + @ToString.Exclude private List junctions; @NonNull @OneToMany(cascade = CascadeType.ALL) + @ToString.Exclude private List fixtures; @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private List pipes; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Components that = (Components) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Connection.java b/backend/src/main/java/net/es/oscars/resv/ent/Connection.java index d47941baa..f0fce8e45 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Connection.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Connection.java @@ -4,14 +4,18 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; import net.es.oscars.resv.enums.*; - -import jakarta.persistence.*; +import org.hibernate.proxy.HibernateProxy; import java.util.List; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -86,6 +90,7 @@ public Connection(@JsonProperty("connectionId") @NonNull String connectionId, @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_NULL) + @ToString.Exclude private List tags; @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) @@ -108,4 +113,20 @@ public Connection(@JsonProperty("connectionId") @NonNull String connectionId, @Transient public ConnectionSouthbound southbound; + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Connection that = (Connection) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Design.java b/backend/src/main/java/net/es/oscars/resv/ent/Design.java index 860b4e8d0..f7bb0e6ec 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Design.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Design.java @@ -4,13 +4,18 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; import lombok.extern.slf4j.Slf4j; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; @Entity -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Builder @AllArgsConstructor @NoArgsConstructor @@ -47,4 +52,19 @@ public Design(@JsonProperty("designId") @NonNull String designId, @JsonInclude(JsonInclude.Include.NON_NULL) private String username; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Design design = (Design) o; + return getId() != null && Objects.equals(getId(), design.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/EroHop.java b/backend/src/main/java/net/es/oscars/resv/ent/EroHop.java index b40a4d7f8..6a6173845 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/EroHop.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/EroHop.java @@ -3,13 +3,17 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import lombok.*; +import org.hibernate.proxy.HibernateProxy; -@Data +import java.util.Objects; + +@Getter +@Setter +@ToString @Builder @NoArgsConstructor @AllArgsConstructor @@ -29,5 +33,19 @@ public EroHop(@JsonProperty("urn") @NonNull String urn) { @NonNull private String urn; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + EroHop eroHop = (EroHop) o; + return getId() != null && Objects.equals(getId(), eroHop.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Event.java b/backend/src/main/java/net/es/oscars/resv/ent/Event.java index f63881b7e..7ef477294 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Event.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Event.java @@ -3,13 +3,20 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; import lombok.*; import net.es.oscars.resv.enums.EventType; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; import java.time.Instant; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -47,4 +54,19 @@ public Event(@JsonProperty("connectionId") @NonNull String connectionId, private String username; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Event event = (Event) o; + return getId() != null && Objects.equals(getId(), event.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/EventLog.java b/backend/src/main/java/net/es/oscars/resv/ent/EventLog.java index 32035c743..259fc3805 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/EventLog.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/EventLog.java @@ -1,13 +1,18 @@ package net.es.oscars.resv.ent; import com.fasterxml.jackson.annotation.*; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; import java.time.Instant; import java.util.List; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -41,7 +46,22 @@ public EventLog(@JsonProperty("connectionId") @NonNull String connectionId, @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private List events; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + EventLog eventLog = (EventLog) o; + return getId() != null && Objects.equals(getId(), eventLog.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Held.java b/backend/src/main/java/net/es/oscars/resv/ent/Held.java index 16071bec7..ac1edcc84 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Held.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Held.java @@ -4,12 +4,17 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; import java.time.Instant; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -32,7 +37,7 @@ public Held(@JsonProperty("connectionId") @NonNull String connectionId, private Long id; @NonNull - @Column(unique = true) + @Column private String connectionId; @NonNull @@ -47,5 +52,19 @@ public Held(@JsonProperty("connectionId") @NonNull String connectionId, @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) private Schedule schedule; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Held held = (Held) o; + return getId() != null && Objects.equals(getId(), held.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Reserved.java b/backend/src/main/java/net/es/oscars/resv/ent/Reserved.java index bfff9b079..45d5526cb 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Reserved.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Reserved.java @@ -3,11 +3,15 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString @Entity @Builder @AllArgsConstructor @@ -38,5 +42,19 @@ public Reserved(@JsonProperty("connectionId") @NonNull String connectionId, @NonNull private Schedule schedule; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Reserved reserved = (Reserved) o; + return getId() != null && Objects.equals(getId(), reserved.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Schedule.java b/backend/src/main/java/net/es/oscars/resv/ent/Schedule.java index fa9f6d378..c08cc8719 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Schedule.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Schedule.java @@ -1,15 +1,20 @@ package net.es.oscars.resv.ent; import com.fasterxml.jackson.annotation.*; -import lombok.*; -import net.es.oscars.resv.enums.Phase; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import lombok.*; +import net.es.oscars.resv.enums.Phase; +import org.hibernate.proxy.HibernateProxy; + import java.time.Instant; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Builder @NoArgsConstructor @AllArgsConstructor @@ -66,4 +71,19 @@ public Boolean overlaps(Instant b, Instant e) { return result; } + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Schedule schedule = (Schedule) o; + return getId() != null && Objects.equals(getId(), schedule.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Tag.java b/backend/src/main/java/net/es/oscars/resv/ent/Tag.java index 5e04e2cb4..96987df6e 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Tag.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Tag.java @@ -1,15 +1,18 @@ package net.es.oscars.resv.ent; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import lombok.*; +import org.hibernate.proxy.HibernateProxy; + +import java.util.Objects; -@Data +@Getter +@Setter +@ToString @Entity @Builder @AllArgsConstructor @@ -32,4 +35,19 @@ public Tag(@JsonProperty("category") @NonNull String category, @NonNull private String contents; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Tag tag = (Tag) o; + return getId() != null && Objects.equals(getId(), tag.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/TagCategory.java b/backend/src/main/java/net/es/oscars/resv/ent/TagCategory.java index 1e7bb4cd2..723fb4a29 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/TagCategory.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/TagCategory.java @@ -1,15 +1,19 @@ package net.es.oscars.resv.ent; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import lombok.*; +import org.hibernate.proxy.HibernateProxy; + +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @AllArgsConstructor @@ -32,4 +36,19 @@ public TagCategory( private String source; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + TagCategory that = (TagCategory) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/Vlan.java b/backend/src/main/java/net/es/oscars/resv/ent/Vlan.java index 019e19aa6..ec4e37106 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/Vlan.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/Vlan.java @@ -4,11 +4,19 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Builder @NoArgsConstructor @AllArgsConstructor @@ -51,5 +59,19 @@ public Vlan(@JsonProperty("connectionId") String connectionId, private Schedule schedule; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Vlan vlan = (Vlan) o; + return getId() != null && Objects.equals(getId(), vlan.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/VlanFixture.java b/backend/src/main/java/net/es/oscars/resv/ent/VlanFixture.java index 58cd93972..cbb98977a 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/VlanFixture.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/VlanFixture.java @@ -4,13 +4,17 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; -import net.es.oscars.resv.enums.EthFixtureType; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; import java.util.Set; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @NoArgsConstructor @@ -79,7 +83,22 @@ public VlanFixture(@JsonProperty("connectionId") String connectionId, @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private Set commandParams; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + VlanFixture that = (VlanFixture) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/VlanJunction.java b/backend/src/main/java/net/es/oscars/resv/ent/VlanJunction.java index 084325a54..0a45f51d1 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/VlanJunction.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/VlanJunction.java @@ -1,12 +1,17 @@ package net.es.oscars.resv.ent; import com.fasterxml.jackson.annotation.*; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; +import java.util.Objects; import java.util.Set; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @NoArgsConstructor @@ -52,6 +57,7 @@ public VlanJunction(@JsonProperty("connectionId") String connectionId, @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private Set commandParams; // really only for reserving a vlanId at a switch @@ -59,4 +65,19 @@ public VlanJunction(@JsonProperty("connectionId") String connectionId, @JsonInclude(JsonInclude.Include.NON_EMPTY) private Vlan vlan; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + VlanJunction that = (VlanJunction) o; + return getId() != null && Objects.equals(getId(), that.getId()); + } + + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/ent/VlanPipe.java b/backend/src/main/java/net/es/oscars/resv/ent/VlanPipe.java index fb326fdf6..7e1630715 100644 --- a/backend/src/main/java/net/es/oscars/resv/ent/VlanPipe.java +++ b/backend/src/main/java/net/es/oscars/resv/ent/VlanPipe.java @@ -4,13 +4,17 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.*; import lombok.*; +import org.hibernate.proxy.HibernateProxy; -import jakarta.persistence.*; import java.util.List; -import java.util.Set; +import java.util.Objects; -@Data +@Getter +@Setter +@ToString +@RequiredArgsConstructor @Entity @Builder @NoArgsConstructor @@ -62,10 +66,12 @@ public VlanPipe(@JsonProperty("connectionId") String connectionId, // EROs are optional @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private List azERO; @OneToMany(cascade = CascadeType.ALL) @JsonInclude(JsonInclude.Include.NON_EMPTY) + @ToString.Exclude private List zaERO; // these will be populated by the system when designing @@ -76,5 +82,19 @@ public VlanPipe(@JsonProperty("connectionId") String connectionId, @JsonInclude(JsonInclude.Include.NON_EMPTY) private Schedule schedule; + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + VlanPipe vlanPipe = (VlanPipe) o; + return getId() != null && Objects.equals(getId(), vlanPipe.getId()); + } + @Override + public final int hashCode() { + return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode(); + } } diff --git a/backend/src/main/java/net/es/oscars/resv/svc/ConnService.java b/backend/src/main/java/net/es/oscars/resv/svc/ConnService.java index 0b46364ef..84bf634be 100644 --- a/backend/src/main/java/net/es/oscars/resv/svc/ConnService.java +++ b/backend/src/main/java/net/es/oscars/resv/svc/ConnService.java @@ -1,6 +1,8 @@ package net.es.oscars.resv.svc; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.Data; import lombok.extern.slf4j.Slf4j; import net.es.oscars.app.exc.PCEException; @@ -24,9 +26,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import jakarta.persistence.EntityNotFoundException; +import org.springframework.transaction.annotation.Transactional; import java.time.*; import java.time.temporal.ChronoUnit; @@ -41,7 +43,6 @@ @Service @Slf4j @Data -@Transactional public class ConnService { @Autowired @@ -312,6 +313,7 @@ public ConnectionSouthbound southbound(String connectionId) { } + @Transactional public void modifySchedule(Connection c, Instant beginning, Instant ending) throws ModifyException { if (!c.getPhase().equals(Phase.RESERVED)) { throw new ModifyException("May only change schedule when RESERVED"); @@ -328,6 +330,7 @@ public void modifySchedule(Connection c, Instant beginning, Instant ending) thro } + @Transactional public void modifyBandwidth(Connection c, Integer bandwidth) throws ModifyException { if (!c.getPhase().equals(Phase.RESERVED)) { throw new ModifyException("May only change schedule when RESERVED"); @@ -441,46 +444,63 @@ public Validity verifyModification(Connection c) { } + @Transactional public ConnChangeResult commit(Connection c) throws NsoResvException, PCEException, ConnException { log.info("committing " + c.getConnectionId()); + ReentrantLock connLock = dbAccess.getConnLock(); + if (connLock.isLocked()) { + log.debug("connection lock already locked; will need to wait to complete commit"); + } + connLock.lock(); + Held h = c.getHeld(); if (!c.getPhase().equals(Phase.HELD)) { + connLock.unlock(); throw new PCEException("Connection not in HELD phase " + c.getConnectionId()); } if (h == null) { + connLock.unlock(); throw new PCEException("Null held " + c.getConnectionId()); } Validity v = this.validateCommit(c); if (!v.isValid()) { + connLock.unlock(); throw new ConnException("Invalid connection for commit; errors follow: \n" + v.getMessage()); } - ReentrantLock connLock = dbAccess.getConnLock(); - if (connLock.isLocked()) { - log.debug("connection lock already locked; will need to wait to complete commit"); - } - connLock.lock(); + try { // log.debug("got connection lock "); c.setPhase(Phase.RESERVED); + c.setArchived(null); - reservedFromHeld(c); - archiveFromReserved(c); - c.setHeld(null); - c.setDeploymentState(DeploymentState.UNDEPLOYED); - c.setDeploymentIntent(DeploymentIntent.SHOULD_BE_UNDEPLOYED); + Connection afterArchiveDeleted = connRepo.save(c); - connRepo.saveAndFlush(c); - nsoResourceService.reserve(c); + // try and delete any previous archived stuff that might exist + archivedRepo.findByConnectionId(afterArchiveDeleted.getConnectionId()).ifPresent(archivedRepo::delete); - connRepo.saveAndFlush(c); + reservedFromHeld(afterArchiveDeleted); + archiveFromReserved(afterArchiveDeleted); + + afterArchiveDeleted.setHeld(null); + // try and delete any held components that might still be around + heldRepo.findByConnectionId(afterArchiveDeleted.getConnectionId()).ifPresent(heldRepo::delete); + + afterArchiveDeleted.setDeploymentState(DeploymentState.UNDEPLOYED); + afterArchiveDeleted.setDeploymentIntent(DeploymentIntent.SHOULD_BE_UNDEPLOYED); Instant instant = Instant.now(); - c.setLast_modified((int) instant.getEpochSecond()); + afterArchiveDeleted.setLast_modified((int) instant.getEpochSecond()); + + dumpDebug("afterArchiveDeleted", afterArchiveDeleted); + + Connection beforeNsoReserve = connRepo.saveAndFlush(afterArchiveDeleted); + nsoResourceService.reserve(beforeNsoReserve); + } finally { // log.debug("unlocked connections"); @@ -504,6 +524,7 @@ public ConnChangeResult commit(Connection c) throws NsoResvException, PCEExcepti } + @Transactional public ConnChangeResult release(Connection c) { // if it is HELD or DESIGN, just delete it if (c.getPhase().equals(Phase.HELD) || c.getPhase().equals(Phase.DESIGN)) { @@ -1093,6 +1114,19 @@ public Connection toNewConnection(SimpleConnection in) { return c; } + private void dumpDebug(String context, Object o) { + String pretty = null; + try { + pretty = (new ObjectMapper()) + .registerModule(new JavaTimeModule()) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (JsonProcessingException ex) { + log.error(ex.getMessage()); + } + + log.info(context + "\n" + pretty); + } } diff --git a/backend/src/main/java/net/es/oscars/topo/pop/TopoPopulator.java b/backend/src/main/java/net/es/oscars/topo/pop/TopoPopulator.java index a1c5a16e7..2808bbf16 100644 --- a/backend/src/main/java/net/es/oscars/topo/pop/TopoPopulator.java +++ b/backend/src/main/java/net/es/oscars/topo/pop/TopoPopulator.java @@ -1,6 +1,5 @@ package net.es.oscars.topo.pop; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import net.es.oscars.app.props.TopoProperties; import net.es.oscars.dto.topo.DeviceModel; @@ -12,14 +11,13 @@ import net.es.oscars.topo.svc.TopologyStore; import net.es.topo.common.model.oscars1.*; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Service; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -import java.io.File; import java.io.IOException; -import java.time.Instant; import java.util.*; @@ -29,15 +27,19 @@ public class TopoPopulator { private final TopoProperties topoProperties; private final TopologyStore topologyStore; private final ConsistencyService consistencySvc; - + private final RestTemplate restTemplate; @Autowired public TopoPopulator(TopologyStore topologyStore, ConsistencyService consistencySvc, - TopoProperties topoProperties) { + TopoProperties topoProperties, + RestTemplateBuilder restTemplateBuilder) { this.topoProperties = topoProperties; this.consistencySvc = consistencySvc; this.topologyStore = topologyStore; + + this.restTemplate = restTemplateBuilder.build(); + } @@ -60,7 +62,8 @@ public void refresh() throws ConsistencyException, TopoException, IOException { public Topology loadFromDiscovery() throws TopoException, ResourceAccessException { log.info("loading topology from discovery"); - RestTemplate restTemplate = new RestTemplate(); + + OscarsOneTopo discTopo = restTemplate.getForObject(topoProperties.getUrl(), OscarsOneTopo.class); if (discTopo == null) { log.warn("null discovery topology"); diff --git a/backend/src/main/java/net/es/oscars/web/rest/HoldController.java b/backend/src/main/java/net/es/oscars/web/rest/HoldController.java index ca0203a65..c89815e5a 100644 --- a/backend/src/main/java/net/es/oscars/web/rest/HoldController.java +++ b/backend/src/main/java/net/es/oscars/web/rest/HoldController.java @@ -188,12 +188,20 @@ public SimpleConnection hold(Authentication authentication, throw new StartupException("OSCARS shutting down"); } + ReentrantLock connLock = dbAccess.getConnLock(); + if (connLock.isLocked()) { + log.debug("connection lock already locked; returning from hold"); + return null; + } + connLock.lock(); + // TODO: Don't throw exception; populate all the Validity entries instead Validity v = connSvc.validate(in, ConnectionMode.NEW); if (!v.isValid()) { in.setValidity(v); log.info("did not update invalid connection "+in.getConnectionId()); log.info("reason: "+v.getMessage()); + connLock.unlock(); return in; } @@ -213,6 +221,7 @@ public SimpleConnection hold(Authentication authentication, Connection prev = maybeConnection.get(); // don't throw an error, just return the input. makes sure if (!prev.getPhase().equals(Phase.HELD)) { + connLock.unlock(); return in; } @@ -221,6 +230,7 @@ public SimpleConnection hold(Authentication authentication, // log.debug("prev conn: "+prev.getId()+"\n" + prettyPrv); updateConnection(in, prev); + log.info("new expiration: "+prev.getHeld().getExpiration()); // String prettyUpd = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(prev); // log.debug("updated conn: "+prev.getId()+"\n" + prettyUpd); @@ -243,6 +253,8 @@ public SimpleConnection hold(Authentication authentication, connRepo.save(c); } + connLock.unlock(); + return in; } diff --git a/backend/src/main/java/net/es/oscars/web/rest/NsoLiveStatusController.java b/backend/src/main/java/net/es/oscars/web/rest/NsoLiveStatusController.java index 89ed008a6..22adcef4f 100644 --- a/backend/src/main/java/net/es/oscars/web/rest/NsoLiveStatusController.java +++ b/backend/src/main/java/net/es/oscars/web/rest/NsoLiveStatusController.java @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import net.es.oscars.resv.enums.DeploymentState; +import net.es.oscars.resv.enums.Phase; import net.es.oscars.resv.enums.State; import net.es.oscars.sb.nso.db.NsoSdpIdDAO; import net.es.oscars.sb.nso.ent.NsoSdpId; @@ -122,14 +123,23 @@ public OperationalStateInfoResponse getOperationalStateInfo(@RequestBody NsoLive int serviceId = requestData.getServiceId(); Connection conn = requestData.getConn(); - // this collects nsoSdpIds that oscars would set up, keyed off the device - List nsoSdpIds = nsoSdpIdDAO.findNsoSdpIdByConnectionId(conn.getConnectionId()); - - // start building REST return OperationalStateInfoResponse response = new OperationalStateInfoResponse(); response.setTimestamp(Instant.now()); response.setConnectionId(request.getConnectionId()); // cp connId from request + boolean canGetLiveStatus = false; + if (conn.getPhase().equals(Phase.RESERVED)) { + if (conn.getState().equals(State.ACTIVE)) { + canGetLiveStatus = true; + } + } + if (!canGetLiveStatus) { + response.setState(OperationalState.DOWN); + return response; + } + + + Instant timestamp = request.getRefreshIfOlderThan(); List results = new ArrayList<>(); @@ -137,6 +147,9 @@ public OperationalStateInfoResponse getOperationalStateInfo(@RequestBody NsoLive Map> allSapsForDevice = new HashMap<>(); // Map> allLspsForDevice = new HashMap<>(); + // this collects nsoSdpIds that oscars would set up, keyed off the device + List nsoSdpIds = nsoSdpIdDAO.findNsoSdpIdByConnectionId(conn.getConnectionId()); + log.debug("Run live-status request on devices and collect operational states"); for (String device : devices) { diff --git a/backend/src/main/java/net/es/oscars/web/rest/SimpleApiController.java b/backend/src/main/java/net/es/oscars/web/rest/SimpleApiController.java index fea0347e9..83e7204ae 100644 --- a/backend/src/main/java/net/es/oscars/web/rest/SimpleApiController.java +++ b/backend/src/main/java/net/es/oscars/web/rest/SimpleApiController.java @@ -118,6 +118,7 @@ public List simpleList(@RequestParam(defaultValue = "0", requi } else if (startup.isInShutdown()) { throw new StartupException("OSCARS shutting down"); } + log.info("retrieving OSCARS connection list"); boolean return_svc_ids = false; if (include_svc_id != null) { diff --git a/deploy/devel/backend.dockerfile b/deploy/devel/backend.dockerfile index 7b864294a..31208f1bc 100644 --- a/deploy/devel/backend.dockerfile +++ b/deploy/devel/backend.dockerfile @@ -44,4 +44,4 @@ COPY --from=builder /build/backend/snapshot-dependencies/ ./ COPY --from=builder /build/backend/application/ ./ # run the application -ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] +ENTRYPOINT ["java","org.springframework.boot.loader.launch.JarLauncher"] \ No newline at end of file diff --git a/deploy/prod/backend.dockerfile b/deploy/prod/backend.dockerfile index cde58f516..7c9d696f7 100644 --- a/deploy/prod/backend.dockerfile +++ b/deploy/prod/backend.dockerfile @@ -41,4 +41,4 @@ COPY --from=builder /build/backend/snapshot-dependencies/ ./ COPY --from=builder /build/backend/application/ ./ # run the application -ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher", "--spring.config.location=/app/config/application.properties"] +ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher", "--spring.config.location=/app/config/application.properties"]