Skip to content

Commit

Permalink
Introduction of Rest Module (Ericsson#784)
Browse files Browse the repository at this point in the history
* Introduction of Rest Module

* Fix Wrong Java Docs
  • Loading branch information
VictorCavichioli authored Dec 6, 2024
1 parent 59713af commit c2ca685
Show file tree
Hide file tree
Showing 30 changed files with 2,765 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Version 1.0.0 (Not yet Released)

* Introduce REST Module for Scheduling and Managing Cassandra Repairs - Issue #771
* Create On Demand Repair Job on Agent - Issue #775
* Modify DistributedNativeConnectionProvider to Return a Map<UUID, Node> - Issue #778
* Bump Spring, Tomcat, Jackson and other dependencies to Remove Vulnerabilities in Agent - Issue #776
Expand Down
6 changes: 6 additions & 0 deletions application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.ericsson.bss.cassandra.ecchronos</groupId>
<artifactId>rest</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
*/
package com.ericsson.bss.cassandra.ecchronos.application;

import com.ericsson.bss.cassandra.ecchronos.rest.OnDemandRepairManagementRESTImpl;
import com.ericsson.bss.cassandra.ecchronos.rest.RepairManagementRESTImpl;
import com.ericsson.bss.cassandra.ecchronos.rest.ScheduleRepairManagementRESTImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import(value = { RepairManagementRESTImpl.class, ScheduleRepairManagementRESTImpl.class,
OnDemandRepairManagementRESTImpl.class })
public class SpringBooter extends SpringBootServletInitializer
{
private static final Logger LOG = LoggerFactory.getLogger(SpringBooter.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
import com.ericsson.bss.cassandra.ecchronos.application.config.repair.FileBasedRepairConfiguration;
import com.ericsson.bss.cassandra.ecchronos.connection.DistributedJmxConnectionProvider;
import com.ericsson.bss.cassandra.ecchronos.connection.DistributedNativeConnectionProvider;
import com.ericsson.bss.cassandra.ecchronos.core.impl.metrics.RepairStatsProviderImpl;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.DefaultRepairConfigurationProvider;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.OnDemandStatus;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.scheduler.OnDemandRepairSchedulerImpl;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.scheduler.RepairSchedulerImpl;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.state.RepairStateFactoryImpl;
import com.ericsson.bss.cassandra.ecchronos.core.impl.repair.vnode.VnodeRepairStateFactoryImpl;
import com.ericsson.bss.cassandra.ecchronos.core.impl.table.TimeBasedRunPolicy;
import com.ericsson.bss.cassandra.ecchronos.core.repair.scheduler.OnDemandRepairScheduler;
import com.ericsson.bss.cassandra.ecchronos.core.repair.RepairStatsProvider;
import com.ericsson.bss.cassandra.ecchronos.core.repair.scheduler.RepairScheduler;
import com.ericsson.bss.cassandra.ecchronos.core.state.ReplicationState;
import com.ericsson.bss.cassandra.ecchronos.core.table.ReplicatedTableProvider;
Expand All @@ -48,6 +51,7 @@ public class ECChronos implements Closeable
private final RepairSchedulerImpl myRepairSchedulerImpl;
private final TimeBasedRunPolicy myTimeBasedRunPolicy;
private final OnDemandRepairSchedulerImpl myOnDemandRepairSchedulerImpl;
private final RepairStatsProvider myRepairStatsProvider;

public ECChronos(
final Config configuration,
Expand Down Expand Up @@ -119,6 +123,9 @@ public ECChronos(
.withDistributedNativeConnectionProvider(nativeConnectionProvider)
.withTableReferenceFactory(myECChronosInternals.getTableReferenceFactory()));

myRepairStatsProvider = new RepairStatsProviderImpl(
nativeConnectionProvider,
new VnodeRepairStateFactoryImpl(replicationState, repairHistoryService, true));
myECChronosInternals.addRunPolicy(myTimeBasedRunPolicy);
}

Expand Down Expand Up @@ -146,6 +153,12 @@ public OnDemandRepairScheduler onDemandRepairScheduler()
return myOnDemandRepairSchedulerImpl;
}

@Bean
public RepairStatsProvider repairStatsProvider()
{
return myRepairStatsProvider;
}

@Override
public final void close()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class DistributedJmxBuilder
{
private static final Logger LOG = LoggerFactory.getLogger(DistributedJmxBuilder.class);
private static final String JMX_FORMAT_URL = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi";
private static final String JMX_JOLOKIA_FORMAT_URL = "service:jmx:jolokia://%s:%d/jolokia";
private static final String JMX_JOLOKIA_FORMAT_URL = "service:jmx:jolokia://%s:%d/jolokia/";
private static final int DEFAULT_JOLOKIA_PORT = 8778;
private static final int DEFAULT_PORT = 7199;

Expand Down Expand Up @@ -212,7 +212,7 @@ public void reconnect(final Node node) throws EcChronosException
}
catch
(
AllNodesFailedException | QueryExecutionException | IOException | SecurityException e)
AllNodesFailedException | QueryExecutionException | IOException | SecurityException e)
{
LOG.error("Failed to create JMX connection with node {} because of {}", node.getHostId(), e.getMessage());
myEccNodesSync.updateNodeStatus(NodeStatus.UNAVAILABLE, node.getDatacenter(), node.getHostId());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2024 Telefonaktiebolaget LM Ericsson
*
* Licensed 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 com.ericsson.bss.cassandra.ecchronos.core.impl.metrics;

import com.datastax.oss.driver.api.core.metadata.Node;
import com.ericsson.bss.cassandra.ecchronos.connection.DistributedNativeConnectionProvider;
import com.ericsson.bss.cassandra.ecchronos.core.repair.RepairStatsProvider;
import com.ericsson.bss.cassandra.ecchronos.core.repair.types.RepairStats;
import com.ericsson.bss.cassandra.ecchronos.core.state.VnodeRepairState;
import com.ericsson.bss.cassandra.ecchronos.core.state.VnodeRepairStateFactory;
import com.ericsson.bss.cassandra.ecchronos.core.state.VnodeRepairStateUtils;
import com.ericsson.bss.cassandra.ecchronos.core.state.VnodeRepairStates;
import com.ericsson.bss.cassandra.ecchronos.core.table.TableReference;
import java.util.Collection;
import java.util.UUID;
import java.util.stream.Collectors;

public class RepairStatsProviderImpl implements RepairStatsProvider
{
private final DistributedNativeConnectionProvider myNativeConnectionProvider;
private final VnodeRepairStateFactory myVnodeRepairStateFactory;

public RepairStatsProviderImpl(
final DistributedNativeConnectionProvider nativeConnectionProvider,
final VnodeRepairStateFactory vnodeRepairStateFactory)
{
myVnodeRepairStateFactory = vnodeRepairStateFactory;
myNativeConnectionProvider = nativeConnectionProvider;
}

@Override
public final RepairStats getRepairStats(
final UUID nodeID,
final TableReference tableReference,
final long since,
final long to)
{
Node node = myNativeConnectionProvider.getNodes().get(nodeID);
VnodeRepairStates vnodeRepairStates;
vnodeRepairStates = myVnodeRepairStateFactory.calculateClusterWideState(node, tableReference, to, since);
Collection<VnodeRepairState> states = vnodeRepairStates.getVnodeRepairStates();
Collection<VnodeRepairState> repairedStates = states.stream()
.filter(s -> isRepaired(s, since, to))
.collect(Collectors.toList());
double repairedRatio = states.isEmpty() ? 0 : (double) repairedStates.size() / states.size();
return new RepairStats(tableReference.getKeyspace(), tableReference.getTable(), repairedRatio,
VnodeRepairStateUtils.getRepairTime(repairedStates));
}

private boolean isRepaired(final VnodeRepairState state, final long since, final long to)
{
return state.getStartedAt() >= since && state.getFinishedAt() <= to;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@

import com.ericsson.bss.cassandra.ecchronos.core.state.HostStates;
import com.ericsson.bss.cassandra.ecchronos.core.state.PostUpdateHook;
import com.ericsson.bss.cassandra.ecchronos.core.state.RepairHistoryProvider;
import com.ericsson.bss.cassandra.ecchronos.core.state.RepairState;
import com.ericsson.bss.cassandra.ecchronos.core.state.RepairStateFactory;
import com.ericsson.bss.cassandra.ecchronos.core.state.ReplicaRepairGroupFactory;
import com.ericsson.bss.cassandra.ecchronos.core.state.ReplicationState;
import com.ericsson.bss.cassandra.ecchronos.core.state.VnodeRepairStateFactory;
import com.ericsson.bss.cassandra.ecchronos.core.table.TableReference;
import com.ericsson.bss.cassandra.ecchronos.core.table.TableRepairMetrics;
import com.ericsson.bss.cassandra.ecchronos.data.repairhistory.RepairHistoryService;

public final class RepairStateFactoryImpl implements RepairStateFactory
{
Expand Down Expand Up @@ -77,7 +77,7 @@ public static class Builder
{
private ReplicationState myReplicationState;
private HostStates myHostStates;
private RepairHistoryService myRepairHistoryProvider;
private RepairHistoryProvider myRepairHistoryProvider;
private TableRepairMetrics myTableRepairMetrics;

/**
Expand Down Expand Up @@ -110,7 +110,7 @@ public Builder withHostStates(final HostStates hostStates)
* @param repairHistoryProvider The repair history provider.
* @return Builder
*/
public Builder withRepairHistoryProvider(final RepairHistoryService repairHistoryProvider)
public Builder withRepairHistoryProvider(final RepairHistoryProvider repairHistoryProvider)
{
myRepairHistoryProvider = repairHistoryProvider;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ public Iterator<ScheduledTask> iterator()
.withTokensPerRepair(tokensPerRepair)
.withRepairPolicies(getRepairPolicies())
.withRepairHistory(myRepairHistory)
.withRepairResourceFactory(getRepairLockType().getLockFactory())
.withRepairLockFactory(REPAIR_LOCK_FACTORY)
.withJobId(getId())
.withNode(myNode);

Expand Down
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
<artifactId>caffeine</artifactId>
</dependency>

<!-- OpenAPI annotations -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>

<!-- Test -->
<dependency>
<groupId>org.junit.vintage</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2024 Telefonaktiebolaget LM Ericsson
*
* Licensed 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 com.ericsson.bss.cassandra.ecchronos.core.repair;

import com.ericsson.bss.cassandra.ecchronos.core.repair.types.RepairStats;
import com.ericsson.bss.cassandra.ecchronos.core.table.TableReference;
import java.util.UUID;

public interface RepairStatsProvider
{
RepairStats getRepairStats(UUID nodeID, TableReference tableReference, long since, long to);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright 2024 Telefonaktiebolaget LM Ericsson
*
* Licensed 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 com.ericsson.bss.cassandra.ecchronos.core.repair.types;

import com.ericsson.bss.cassandra.ecchronos.core.repair.scheduler.OnDemandRepairJobView;
import com.ericsson.bss.cassandra.ecchronos.utils.enums.repair.RepairType;
import com.google.common.annotations.VisibleForTesting;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import java.util.Objects;
import java.util.UUID;


/**
* A representation of an on demand repair.
*
* Primarily used to have a type to convert to JSON.
*/
@SuppressWarnings("VisibilityModifier")
public class OnDemandRepair
{
@NotBlank
public UUID id;
@NotBlank
public UUID hostId;
@NotBlank
public String keyspace;
@NotBlank
public String table;
@NotBlank
public OnDemandRepairJobView.Status status;
@NotBlank
@Min(0)
@Max(1)
public double repairedRatio;
@NotBlank
@Min(-1)
public long completedAt;
@NotBlank
public RepairType repairType;

public OnDemandRepair()
{
}

@VisibleForTesting
public OnDemandRepair(final UUID theId,
final UUID theHostId,
final String theKeyspace,
final String theTable,
final OnDemandRepairJobView.Status theStatus,
final double theRepairedRatio,
final long wasCompletedAt,
final RepairType theRepairType)
{
this.id = theId;
this.hostId = theHostId;
this.keyspace = theKeyspace;
this.table = theTable;
this.status = theStatus;
this.repairedRatio = theRepairedRatio;
this.completedAt = wasCompletedAt;
this.repairType = theRepairType;
}


public OnDemandRepair(final OnDemandRepairJobView repairJobView)
{
this.id = repairJobView.getId();
this.hostId = repairJobView.getHostId();
this.keyspace = repairJobView.getTableReference().getKeyspace();
this.table = repairJobView.getTableReference().getTable();
this.status = repairJobView.getStatus();
this.repairedRatio = repairJobView.getProgress();
this.completedAt = repairJobView.getCompletionTime();
this.repairType = repairJobView.getRepairType();
}

/**
* Equality.
*
* @param o The object to compare to.
* @return boolean
*/
@Override
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
OnDemandRepair that = (OnDemandRepair) o;
return id.equals(that.id)
&& hostId.equals(that.hostId)
&& keyspace.equals(that.keyspace)
&& table.equals(that.table)
&& status == that.status
&& Double.compare(that.repairedRatio, repairedRatio) == 0
&& completedAt == that.completedAt
&& repairType.equals(that.repairType);
}

/**
* Hash code representation.
*
* @return int
*/
@Override
public int hashCode()
{
return Objects.hash(id, hostId, keyspace, table, repairedRatio, status, completedAt, repairType);
}
}
Loading

0 comments on commit c2ca685

Please sign in to comment.