Skip to content

Commit

Permalink
Merge e8629a1 into f3004e8
Browse files Browse the repository at this point in the history
  • Loading branch information
mprimi committed Mar 31, 2020
2 parents f3004e8 + e8629a1 commit 9182aea
Show file tree
Hide file tree
Showing 12 changed files with 712 additions and 28 deletions.
@@ -0,0 +1,51 @@
/*
*
* Copyright 2020 Netflix, Inc.
*
* 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.netflix.genie.web.services;

/**
* Service interface for the abstracts the details of leadership within nodes in a Genie cluster.
*
* @author mprimi
* @since 4.0.0
*/
public interface ClusterLeaderService {

/**
* Stop the service (i.e. renounce leadership and leave the election).
*/
void stop();

/**
* Start the service (i.e. join the the election).
*/
void start();

/**
* Whether or not this node is participating in the cluster leader election.
*
* @return true if the node is participating in leader election
*/
boolean isRunning();

/**
* Whether or not this node is the current cluster leader.
*
* @return true if the node is the current cluster leader
*/
boolean isLeader();
}
@@ -0,0 +1,74 @@
/*
*
* Copyright 2020 Netflix, Inc.
*
* 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.netflix.genie.web.services.impl;

import com.netflix.genie.web.services.ClusterLeaderService;
import org.springframework.integration.zookeeper.leader.LeaderInitiator;

/**
* Implementation of {@link ClusterLeaderService} using Spring's {@link LeaderInitiator} (Zookeeper/Curator based
* leader election mechanism).
*
* @author mprimi
* @since 4.0.0
*/
public class ClusterLeaderServiceCuratorImpl implements ClusterLeaderService {

private LeaderInitiator leaderInitiator;

/**
* Constructor.
*
* @param leaderInitiator the leader initiator component
*/
public ClusterLeaderServiceCuratorImpl(final LeaderInitiator leaderInitiator) {
this.leaderInitiator = leaderInitiator;
}

/**
* {@inheritDoc}
*/
@Override
public void stop() {
this.leaderInitiator.stop();
}

/**
* {@inheritDoc}
*/
@Override
public void start() {
this.leaderInitiator.start();
}

/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return this.leaderInitiator.isRunning();
}

/**
* {@inheritDoc}
*/
@Override
public boolean isLeader() {
return this.leaderInitiator.getContext().isLeader();
}
}
@@ -0,0 +1,72 @@
/*
*
* Copyright 2020 Netflix, Inc.
*
* 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.netflix.genie.web.services.impl;

import com.netflix.genie.web.services.ClusterLeaderService;
import com.netflix.genie.web.tasks.leader.LocalLeader;

/**
* Implementation of {@link ClusterLeaderService} using statically configured {@link LocalLeader} module.
*
* @author mprimi
* @since 4.0.0
*/
public class ClusterLeaderServiceLocalLeaderImpl implements ClusterLeaderService {
private final LocalLeader localLeader;

/**
* Constructor.
*
* @param localLeader the local leader module
*/
public ClusterLeaderServiceLocalLeaderImpl(final LocalLeader localLeader) {
this.localLeader = localLeader;
}

/**
* {@inheritDoc}
*/
@Override
public void stop() {
this.localLeader.stop();
}

/**
* {@inheritDoc}
*/
@Override
public void start() {
this.localLeader.start();
}

/**
* {@inheritDoc}
*/
@Override
public boolean isRunning() {
return this.localLeader.isRunning();
}

/**
* {@inheritDoc}
*/
@Override
public boolean isLeader() {
return this.localLeader.isLeader();
}
}
@@ -0,0 +1,117 @@
/*
*
* Copyright 2020 Netflix, Inc.
*
* 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.netflix.genie.web.spring.actuators;

import com.google.common.collect.ImmutableMap;
import com.netflix.genie.web.services.ClusterLeaderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;

import java.util.Map;


/**
* An actuator endpoint that exposes leadership status and allows stop/start/restart of the leader election service.
* Useful when a specific set of nodes should be given priority to win the leader election (e.g., because they are
* running newer code).
*
* @since 4.0.0
* @author mprimi
*/
@Endpoint(id = "leaderElection")
@Slf4j
public class LeaderElectionActuator {

/**
* Operations that this actuator can perform on the leader service.
*/
public enum Action {
/**
* Stop the leader election service.
*/
STOP,
/**
* Start the leader election service.
*/
START,
/**
* Stop then start the leader election service.
*/
RESTART,

/**
* NOOP action for the purpose of testing unknown actions.
*/
TEST,
}

private static final String RUNNING = "running";
private static final String LEADER = "leader";
private final ClusterLeaderService clusterLeaderService;

/**
* Constructor.
*
* @param clusterLeaderService the cluster leader service
*/
public LeaderElectionActuator(final ClusterLeaderService clusterLeaderService) {
this.clusterLeaderService = clusterLeaderService;
}

/**
* Provides the current leader service status: whether the leader service is running and whether the node is leader.
*
* @return a map of attributes
*/
@ReadOperation
public Map<String, Object> getStatus() {
return ImmutableMap.<String, Object>builder()
.put(RUNNING, this.clusterLeaderService.isRunning())
.put(LEADER, this.clusterLeaderService.isLeader())
.build();
}

/**
* Forces the node to leave the leader election, then re-join it.
*
* @param action the action to perform
*/
@WriteOperation
public void doAction(final Action action) {
switch (action) {
case START:
log.info("Starting leader election service");
this.clusterLeaderService.start();
break;
case STOP:
log.info("Stopping leader election service");
this.clusterLeaderService.stop();
break;
case RESTART:
log.info("Restarting leader election service");
this.clusterLeaderService.stop();
this.clusterLeaderService.start();
break;
default:
log.error("Unknown action: " + action);
throw new UnsupportedOperationException("Unknown action: " + action.name());
}
}
}
@@ -0,0 +1,28 @@
/*
*
* Copyright 2020 Netflix, Inc.
*
* 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.
*
*/

/**
* Actuator endpoints.
*
* @author mprimi
* @since 4.0.0
*/
@ParametersAreNonnullByDefault
package com.netflix.genie.web.spring.actuators;

import javax.annotation.ParametersAreNonnullByDefault;

0 comments on commit 9182aea

Please sign in to comment.